EDN Admin
Well-known member
Disclaimer: Yes, I know that the vast majority of code need not worry about optimization... it just doesnt matter. Correctness and maintainability are far more important. But there usually is a 3% of code that you do need to worry about
optimization... because if you dont, itll make the overall user experience a bad one.
In <a title="another thread http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/ae263209-d5bb-4e8c-9bdb-0f44fa2fc9ba?prof=required" target="_blank
another thread we have been discussing speed of operators and inlining... and studying that has lead me down a path of looking at the very different expectations regarding optimization that I should have as a .NET / C# developer rather than my former life
as a traditional C++ developer.
In C++ with modern compiler technology, you could be pretty sloppy optimization-wise. For example, you could write foo->bar->baz->doOneThing() and on the next line write foo->bar->baz->doAnotherThing() and know that the compiler would
reliably do foo->bar-baz just once, hold the result in a register, and make the two calls off that pointer. Often I would see loops where code could be moved outside the loop by adding a few extra local vars, but wouldnt bother rewriting that persons
code because I knew the compiler would do it for me. In C++, having layers of classes with layers of functions that just call other functions is common... and with no worries as we know that will all be inlined away.
In C#, it seems the C# compiler does very little (or possibly no) optimization, leaving that for the JIT Compiler. But the JIT Compiler is somewhat limited in the sophistication of the optimization that it can do. It can do more than peephole
optimization, but it is limited to fairly local optimization and fairly local heuristics. For example, the inlining heuristics can recognize code in an inner loop, but not code in an equivalent recursion.
In fact, based on looking at code regarding inlining, it seems many of the fairly local optimizations are not performed. So that many of the things Id have ignored in C++, I need to be hand-optimizing as a programmer in C#. Initially, I was
thinking thats "horrible"... but as I started thinking about the hand optimizations that I need to do, it occurred to me that many of those things (although extra work for the programmer) arguably improve readability and thus maintainability.
For example, common sub-expression elimination requires you to watch for that, and add extra lines of code with extra local variables. But it eliminates cut-n-paste sub-expressions (no worry about changing one and forgetting to change the others) and
gives you a local variable name that explains your intent/expectation to the reader. And that can make debugging easier as you have extra places to put breakpoints and extra variables you can watch. Hmmm....
Pondering that reminded me of my excursion into the Code Analysis rules that MS programmed in for us. For example, one rule I thought was moronic complains about code in constructors where you initialize things to zero. It tells you "The code
will run faster if you dont set values to zero as they are pre-initialzed to zero by the system anyway." I thought that was stupid because that would be a trivial optimization of the compiler... so, why force the user to do that... and further, I believe
its good documentation to have those lines in there (so you know I intended to initialize those to zero... I didnt just forget). So, now I just comment out all such lines so readers know my intent, but Code Analysis doesnt complain. I considered
turning off that rule, but thought there might be a good reason for it...
Now I realize there is a good reason for it: the C# / .NET environment doesnt give you the same level of optimizations.
Putting all that together, I see a potentially very different way of getting the sophisticated optimization of the traditional C++ world with some side benefits:
Move many of the traditional optimizations into Code Analysis rules encouraging programmers to perform those optimizations on their code... with the side benefit that it reduces the maintained code and improves readability and debuggability and so on.
And maybe that was MSs intent... I need to go back through the Code Analysis rules with that idea in mind... maybe a lot of those rules will make more sense now.
On the other hand, theres a number of optimizations that traditional compilers do that would be BAD for readability or would require breaking object-oriented abstractions and such. Those sorts of optimizations do not belong in Code Analysis and may
not be possible to do in the JIT Compiler... those really should be performed by the C# Compiler going to IL code. Maybe well get that someday.
Anyway, now for my QUESTION... all of the above is me drawing conclusions from what I am seeing in analyzing the speed of the code generated for certain key methods and operators and structs and such in my code. Has the MS CLR / compiler team
ever issued:
(1) A document explaining their intent for optimizations in the JIT-compiled world of .NET?
(2) A document listing which of the traditional optimizations the JIT does, which of the traditional optimizations they put in the compiler that generates IL, and which of the traditional optimizations they moved into Code Analysis?
Or has anybody else done like I am doing and figured it out from whats happening and documented that anywhere?
View the full article
optimization... because if you dont, itll make the overall user experience a bad one.
In <a title="another thread http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/ae263209-d5bb-4e8c-9bdb-0f44fa2fc9ba?prof=required" target="_blank
another thread we have been discussing speed of operators and inlining... and studying that has lead me down a path of looking at the very different expectations regarding optimization that I should have as a .NET / C# developer rather than my former life
as a traditional C++ developer.
In C++ with modern compiler technology, you could be pretty sloppy optimization-wise. For example, you could write foo->bar->baz->doOneThing() and on the next line write foo->bar->baz->doAnotherThing() and know that the compiler would
reliably do foo->bar-baz just once, hold the result in a register, and make the two calls off that pointer. Often I would see loops where code could be moved outside the loop by adding a few extra local vars, but wouldnt bother rewriting that persons
code because I knew the compiler would do it for me. In C++, having layers of classes with layers of functions that just call other functions is common... and with no worries as we know that will all be inlined away.
In C#, it seems the C# compiler does very little (or possibly no) optimization, leaving that for the JIT Compiler. But the JIT Compiler is somewhat limited in the sophistication of the optimization that it can do. It can do more than peephole
optimization, but it is limited to fairly local optimization and fairly local heuristics. For example, the inlining heuristics can recognize code in an inner loop, but not code in an equivalent recursion.
In fact, based on looking at code regarding inlining, it seems many of the fairly local optimizations are not performed. So that many of the things Id have ignored in C++, I need to be hand-optimizing as a programmer in C#. Initially, I was
thinking thats "horrible"... but as I started thinking about the hand optimizations that I need to do, it occurred to me that many of those things (although extra work for the programmer) arguably improve readability and thus maintainability.
For example, common sub-expression elimination requires you to watch for that, and add extra lines of code with extra local variables. But it eliminates cut-n-paste sub-expressions (no worry about changing one and forgetting to change the others) and
gives you a local variable name that explains your intent/expectation to the reader. And that can make debugging easier as you have extra places to put breakpoints and extra variables you can watch. Hmmm....
Pondering that reminded me of my excursion into the Code Analysis rules that MS programmed in for us. For example, one rule I thought was moronic complains about code in constructors where you initialize things to zero. It tells you "The code
will run faster if you dont set values to zero as they are pre-initialzed to zero by the system anyway." I thought that was stupid because that would be a trivial optimization of the compiler... so, why force the user to do that... and further, I believe
its good documentation to have those lines in there (so you know I intended to initialize those to zero... I didnt just forget). So, now I just comment out all such lines so readers know my intent, but Code Analysis doesnt complain. I considered
turning off that rule, but thought there might be a good reason for it...
Now I realize there is a good reason for it: the C# / .NET environment doesnt give you the same level of optimizations.
Putting all that together, I see a potentially very different way of getting the sophisticated optimization of the traditional C++ world with some side benefits:
Move many of the traditional optimizations into Code Analysis rules encouraging programmers to perform those optimizations on their code... with the side benefit that it reduces the maintained code and improves readability and debuggability and so on.
And maybe that was MSs intent... I need to go back through the Code Analysis rules with that idea in mind... maybe a lot of those rules will make more sense now.
On the other hand, theres a number of optimizations that traditional compilers do that would be BAD for readability or would require breaking object-oriented abstractions and such. Those sorts of optimizations do not belong in Code Analysis and may
not be possible to do in the JIT Compiler... those really should be performed by the C# Compiler going to IL code. Maybe well get that someday.
Anyway, now for my QUESTION... all of the above is me drawing conclusions from what I am seeing in analyzing the speed of the code generated for certain key methods and operators and structs and such in my code. Has the MS CLR / compiler team
ever issued:
(1) A document explaining their intent for optimizations in the JIT-compiled world of .NET?
(2) A document listing which of the traditional optimizations the JIT does, which of the traditional optimizations they put in the compiler that generates IL, and which of the traditional optimizations they moved into Code Analysis?
Or has anybody else done like I am doing and figured it out from whats happening and documented that anywhere?
View the full article