dotnet performance:
Operator overloading is a nice feature for things like vector and matrix libraries, but I have found that the performance is so low that I can not use it. I have appended a small sample program to illustrate the effect. The performance of the loop using operator overloading is 1/4 of the loop using the ugly c-style static method. It seems that as of now there are two choices in .NET: use all the nice abstractions such as properties, operator overloading and indexers and accept the resulting horrible performance, or write ugly c-style code using lots of ref parameters and direct member access and get acceptable performance. When I use C++ I can use nice abstractions like operator overloading without suffering a large performance penalty. I see no technical reason why this should not be possible in .NET. This is a big problem for me. I wrote a vector and matrix library that makes heavy use of operator overloading. Now I have to decide wether to rewrite everything using ugly C style to get decent performance, or just wait until the performance of the .NET JIT-Compiler becomes acceptable. The question is: when will the performance improve? regards,
I disagree. Your test is not fair. With static methods, you're providing three vectors, the ones that need to be added and the one in which the result is stored. With operator overloading, you're returning a Vector object. Do the same with the static methods and you'll see there's no difference. The point is, it's not because of operator overloading that you're seeing this difference, it's because of the way you designed your program. The design of a program has a large affect on overall performance. Now consider an equation like this: c = sqrt((a/b*c)-d%e) You'll spend the rest of your life debugging equations like these. -Andre [quoted text, click to view] Rüdiger Klaehn wrote: > Operator overloading is a nice feature for things like vector and matrix > libraries, but I have found that the performance is so low that I can not > use it. > > I have appended a small sample program to illustrate the effect. The > performance of the loop using operator overloading is 1/4 of the loop using > the ugly c-style static method. > > It seems that as of now there are two choices in .NET: use all the nice > abstractions such as properties, operator overloading and indexers and > accept the resulting horrible performance, or write ugly c-style code using > lots of ref parameters and direct member access and get acceptable > performance. > > When I use C++ I can use nice abstractions like operator overloading without > suffering a large performance penalty. I see no technical reason why this > should not be possible in .NET. > > This is a big problem for me. I wrote a vector and matrix library that makes > heavy use of operator overloading. Now I have to decide wether to rewrite > everything using ugly C style to get decent performance, or just wait until > the performance of the .NET JIT-Compiler becomes acceptable. > > The question is: when will the performance improve? > > regards, > > Rüdiger Klaehn > > > ------------------------------------------------------------------------ > > using System; > > namespace StructBench > { > public struct Vector3 > { > private double x,y,z; > public Vector3(double x,double y,double z) > { > this.x=x; > this.y=y; > this.z=z; > } > public static void Sum(ref Vector3 a,ref Vector3 b,out Vector3 c) > { > c.x=a.x+b.x; > c.y=a.y+b.y; > c.z=a.z+b.z; > } > public static Vector3 operator + (Vector3 a,Vector3 b) > { > return new Vector3(a.x+b.x,a.y+b.y,a.z+b.z); > } > } > public class Benchmark > { > public static void Main(string[] args) > { > System.Threading.Thread.CurrentThread.Priority=System.Threading.ThreadPriority.Highest; > Vector3 a=new Vector3(1,2,3); > Vector3 b=new Vector3(4,5,6); > Vector3 c; > DateTime time0=DateTime.Now; > for(int i=0;i<1000000;i++) > c=a+b; > TimeSpan delta0=DateTime.Now-time0; > DateTime time1=DateTime.Now; > for(int i=0;i<1000000;i++) > Vector3.Sum(ref a,ref b,out c); > TimeSpan delta1=DateTime.Now-time1; > Console.WriteLine(System.Runtime.InteropServices.RuntimeEnvironment.GetSystemVersion()); > Console.WriteLine("vector addition using c=a+b\n{0} per second",1000000/delta0.TotalSeconds); > Console.WriteLine("vector addition using Vector3.Sum(ref a,ref b,out c)\n{0} per second",1000000/delta1.TotalSeconds); > Console.ReadLine(); > } > } > }
[quoted text, click to view] > You'll spend the rest of your life debugging equations like these.
By this I meant if you have similar looking lines in your code: [quoted text, click to view] >> Vector3.Sum(ref a,ref b,out c);
also note that you would essentially want to return an object of type Vector in your static sum() method if you're thinking about serious reuse of your library. In effect, you would see similar results as to what you saw with operator overloading. -Andre [quoted text, click to view] Andre wrote: > I disagree. Your test is not fair. With static methods, you're providing > three vectors, the ones that need to be added and the one in which the > result is stored. With operator overloading, you're returning a Vector > object. Do the same with the static methods and you'll see there's no > difference. > > The point is, it's not because of operator overloading that you're > seeing this difference, it's because of the way you designed your > program. The design of a program has a large affect on overall > performance. Now consider an equation like this: c = sqrt((a/b*c)-d%e) > > You'll spend the rest of your life debugging equations like these. > > -Andre > > > Rüdiger Klaehn wrote: > >> Operator overloading is a nice feature for things like vector and matrix >> libraries, but I have found that the performance is so low that I can not >> use it. >> I have appended a small sample program to illustrate the effect. The >> performance of the loop using operator overloading is 1/4 of the loop >> using >> the ugly c-style static method. >> >> It seems that as of now there are two choices in .NET: use all the nice >> abstractions such as properties, operator overloading and indexers and >> accept the resulting horrible performance, or write ugly c-style code >> using >> lots of ref parameters and direct member access and get acceptable >> performance. >> >> When I use C++ I can use nice abstractions like operator overloading >> without >> suffering a large performance penalty. I see no technical reason why this >> should not be possible in .NET. >> >> This is a big problem for me. I wrote a vector and matrix library that >> makes >> heavy use of operator overloading. Now I have to decide wether to rewrite >> everything using ugly C style to get decent performance, or just wait >> until >> the performance of the .NET JIT-Compiler becomes acceptable. >> >> The question is: when will the performance improve? >> >> regards, >> >> Rüdiger Klaehn >> >> >> ------------------------------------------------------------------------ >> >> using System; >> >> namespace StructBench { >> public struct Vector3 { >> private double x,y,z; >> public Vector3(double x,double y,double z) { >> this.x=x; >> this.y=y; >> this.z=z; >> } >> public static void Sum(ref Vector3 a,ref Vector3 b,out Vector3 c) >> { >> c.x=a.x+b.x; >> c.y=a.y+b.y; >> c.z=a.z+b.z; >> } >> public static Vector3 operator + (Vector3 a,Vector3 b) { >> return new Vector3(a.x+b.x,a.y+b.y,a.z+b.z); >> } >> } >> public class Benchmark { >> public static void Main(string[] args) { >> >> System.Threading.Thread.CurrentThread.Priority=System.Threading.ThreadPriority.Highest; >> >> Vector3 a=new Vector3(1,2,3); >> Vector3 b=new Vector3(4,5,6); >> Vector3 c; >> DateTime time0=DateTime.Now; >> for(int i=0;i<1000000;i++) >> c=a+b; >> TimeSpan delta0=DateTime.Now-time0; >> DateTime time1=DateTime.Now; >> for(int i=0;i<1000000;i++) >> Vector3.Sum(ref a,ref b,out c); >> TimeSpan delta1=DateTime.Now-time1; >> >> Console.WriteLine(System.Runtime.InteropServices.RuntimeEnvironment.GetSystemVersion()); >> >> Console.WriteLine("vector addition using c=a+b\n{0} per >> second",1000000/delta0.TotalSeconds); >> Console.WriteLine("vector addition using Vector3.Sum(ref a,ref >> b,out c)\n{0} per second",1000000/delta1.TotalSeconds); >> Console.ReadLine(); >> } >> } >> } > >
Sorry for multiple posts :) but.. [quoted text, click to view] Andre wrote: > > You'll spend the rest of your life debugging equations like these. > > By this I meant if you have similar looking lines in your code: > > >> Vector3.Sum(ref a,ref b,out c); > > also note that you would essentially want to return an object of type > Vector in your static sum() method if you're thinking about serious
remove the word "static" from "static sum()".. my mistake [quoted text, click to view] > reuse of your library. In effect, you would see similar results as to > what you saw with operator overloading. > > -Andre > > Andre wrote: > >> I disagree. Your test is not fair. With static methods, you're >> providing three vectors, the ones that need to be added and the one in >> which the result is stored. With operator overloading, you're >> returning a Vector object. Do the same with the static methods and >> you'll see there's no difference. >> >> The point is, it's not because of operator overloading that you're >> seeing this difference, it's because of the way you designed your >> program. The design of a program has a large affect on overall >> performance. Now consider an equation like this: c = sqrt((a/b*c)-d%e) >> >> You'll spend the rest of your life debugging equations like these. >> >> -Andre >> >> >> Rüdiger Klaehn wrote: >> >>> Operator overloading is a nice feature for things like vector and matrix >>> libraries, but I have found that the performance is so low that I can >>> not >>> use it. >>> I have appended a small sample program to illustrate the effect. The >>> performance of the loop using operator overloading is 1/4 of the loop >>> using >>> the ugly c-style static method. >>> >>> It seems that as of now there are two choices in .NET: use all the nice >>> abstractions such as properties, operator overloading and indexers and >>> accept the resulting horrible performance, or write ugly c-style code >>> using >>> lots of ref parameters and direct member access and get acceptable >>> performance. >>> >>> When I use C++ I can use nice abstractions like operator overloading >>> without >>> suffering a large performance penalty. I see no technical reason why >>> this >>> should not be possible in .NET. >>> >>> This is a big problem for me. I wrote a vector and matrix library >>> that makes >>> heavy use of operator overloading. Now I have to decide wether to >>> rewrite >>> everything using ugly C style to get decent performance, or just wait >>> until >>> the performance of the .NET JIT-Compiler becomes acceptable. >>> >>> The question is: when will the performance improve? >>> >>> regards, >>> >>> Rüdiger Klaehn >>> >>> >>> ------------------------------------------------------------------------ >>> >>> using System; >>> >>> namespace StructBench { >>> public struct Vector3 { >>> private double x,y,z; >>> public Vector3(double x,double y,double z) { >>> this.x=x; >>> this.y=y; >>> this.z=z; >>> } >>> public static void Sum(ref Vector3 a,ref Vector3 b,out Vector3 c) >>> { >>> c.x=a.x+b.x; >>> c.y=a.y+b.y; >>> c.z=a.z+b.z; >>> } >>> public static Vector3 operator + (Vector3 a,Vector3 b) { >>> return new Vector3(a.x+b.x,a.y+b.y,a.z+b.z); >>> } >>> } >>> public class Benchmark { >>> public static void Main(string[] args) { >>> >>> System.Threading.Thread.CurrentThread.Priority=System.Threading.ThreadPriority.Highest; >>> >>> Vector3 a=new Vector3(1,2,3); >>> Vector3 b=new Vector3(4,5,6); >>> Vector3 c; >>> DateTime time0=DateTime.Now; >>> for(int i=0;i<1000000;i++) >>> c=a+b; >>> TimeSpan delta0=DateTime.Now-time0; >>> DateTime time1=DateTime.Now; >>> for(int i=0;i<1000000;i++) >>> Vector3.Sum(ref a,ref b,out c); >>> TimeSpan delta1=DateTime.Now-time1; >>> >>> Console.WriteLine(System.Runtime.InteropServices.RuntimeEnvironment.GetSystemVersion()); >>> >>> Console.WriteLine("vector addition using c=a+b\n{0} per >>> second",1000000/delta0.TotalSeconds); >>> Console.WriteLine("vector addition using Vector3.Sum(ref >>> a,ref b,out c)\n{0} per second",1000000/delta1.TotalSeconds); >>> Console.ReadLine(); >>> } >>> } >>> } >> >> >> >
[quoted text, click to view] Andre wrote: > I disagree. Your test is not fair. With static methods, you're providing > three vectors, the ones that need to be added and the one in which the > result is stored. With operator overloading, you're returning a Vector > object. Do the same with the static methods and you'll see there's no > difference. >
Of course the two methods work different. One is ugly and fast, the other one looks good but is slow as hell. The way operator overloading works in .NET, I have no choice but to create a temporary object for the return value. This should be no big deal since it is a struct and thus created on the stack. The JIT-compiler should see that it is just a temporary struct and optimize it away. But it does not. That is the problem. If you do not believe me, try the above sample in C++. You will see that both loops run at exactly the same speed. In fact a good C++ compiler might optimize away the loop completely since the vector c is not used after the loop. regards,
Rüdiger is correct, these are limitations in the current JIT compiler . Of course, we're not happy about them. They should be addressed in the future. -- David Notario Software Design Engineer - CLR JIT Compiler http://xplsv.com/blogs/devdiary/ [quoted text, click to view] "Rüdiger Klaehn" <klaehn@gamemakers.de> wrote in message news:bikgbc$a5tdq$1@ID-152049.news.uni-berlin.de... > Andre wrote: > > > I disagree. Your test is not fair. With static methods, you're providing > > three vectors, the ones that need to be added and the one in which the > > result is stored. With operator overloading, you're returning a Vector > > object. Do the same with the static methods and you'll see there's no > > difference. > > > Of course the two methods work different. One is ugly and fast, the other > one looks good but is slow as hell. > > The way operator overloading works in .NET, I have no choice but to create a > temporary object for the return value. This should be no big deal since it > is a struct and thus created on the stack. The JIT-compiler should see that > it is just a temporary struct and optimize it away. But it does not. That > is the problem. > > If you do not believe me, try the above sample in C++. You will see that > both loops run at exactly the same speed. In fact a good C++ compiler might > optimize away the loop completely since the vector c is not used after the > loop. > > regards, > > Rüdiger
Don't see what you're looking for? Try a search.
|