Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is the C# compiler smart enough to optimize this code?

Please ignore code readability in this question.

In terms of performance, should the following code be written like this:

int maxResults = criteria.MaxResults;  if (maxResults > 0) {     while (accounts.Count > maxResults)         accounts.RemoveAt(maxResults); }

or like this:

if (criteria.MaxResults > 0) {     while (accounts.Count > criteria.MaxResults)         accounts.RemoveAt(criteria.MaxResults); }

?

Edit: criteria is a class, and MaxResults is a simple integer property (i.e., public int MaxResults { get { return _maxResults; } }.

Does the C# compiler treat MaxResults as a black box and evaluate it every time? Or is it smart enough to figure out that I've got 3 calls to the same property with no modification of that property between the calls? What if MaxResults was a field?

One of the laws of optimization is precalculation, so I instinctively wrote this code like the first listing, but I'm curious if this kind of thing is being done for me automatically (again, ignore code readability).

(Note: I'm not interested in hearing the 'micro-optimization' argument, which may be valid in the specific case I've posted. I'd just like some theory behind what's going on or not going on.)

like image 890
Jon Seigel Avatar asked Jan 29 '10 14:01

Jon Seigel


People also ask

Is there a C+?

C+ (grade), an academic grade. C++, a programming language. C with Classes, predecessor to the C++ programming language. ANSI C, a programming language (as opposed to K&R C)

What is C short note?

What Does C Programming Language (C) Mean? C is a high-level and general-purpose programming language that is ideal for developing firmware or portable applications. Originally intended for writing system software, C was developed at Bell Labs by Dennis Ritchie for the Unix Operating System in the early 1970s.

Why is C not A or B?

Because C comes after B The reason why the language was named “C” by its creator was that it came after B language. Back then, Bell Labs already had a programming language called “B” at their disposal.


2 Answers

First off, the only way to actually answer performance questions is to actually try it both ways and test the results in realistic conditions.

That said, the other answers which say that "the compiler" does not do this optimization because the property might have side effects are both right and wrong. The problem with the question (aside from the fundamental problem that it simply cannot be answered without actually trying it and measuring the result) is that "the compiler" is actually two compilers: the C# compiler, which compiles to MSIL, and the JIT compiler, which compiles IL to machine code.

The C# compiler never ever does this sort of optimization; as noted, doing so would require that the compiler peer into the code being called and verify that the result it computes does not change over the lifetime of the callee's code. The C# compiler does not do so.

The JIT compiler might. No reason why it couldn't. It has all the code sitting right there. It is completely free to inline the property getter, and if the jitter determines that the inlined property getter returns a value that can be cached in a register and re-used, then it is free to do so. (If you don't want it to do so because the value could be modified on another thread then you already have a race condition bug; fix the bug before you worry about performance.)

Whether the jitter actually does inline the property fetch and then enregister the value, I have no idea. I know practically nothing about the jitter. But it is allowed to do so if it sees fit. If you are curious about whether it does so or not, you can either (1) ask someone who is on the team that wrote the jitter, or (2) examine the jitted code in the debugger.

And finally, let me take this opportunity to note that computing results once, storing the result and re-using it is not always an optimization. This is a surprisingly complicated question. There are all kinds of things to optimize for:

  • execution time

  • executable code size -- this has a major effect on executable time because big code takes longer to load, increases the working set size, puts pressure on processor caches, RAM and the page file. Small slow code is often in the long run faster than big fast code in important metrics like startup time and cache locality.

  • register allocation -- this also has a major effect on execution time, particularly in architectures like x86 which have a small number of available registers. Enregistering a value for fast re-use can mean that there are fewer registers available for other operations that need optimization; perhaps optimizing those operations instead would be a net win.

  • and so on. It get real complicated real fast.

In short, you cannot possibly know whether writing the code to cache the result rather than recomputing it is actually (1) faster, or (2) better performing. Better performance does not always mean making execution of a particular routine faster. Better performance is about figuring out what resources are important to the user -- execution time, memory, working set, startup time, and so on -- and optimizing for those things. You cannot do that without (1) talking to your customers to find out what they care about, and (2) actually measuring to see if your changes are having a measurable effect in the desired direction.

like image 119
Eric Lippert Avatar answered Sep 20 '22 21:09

Eric Lippert


If MaxResults is a property then no, it will not optimize it, because the getter may have complex logic, say:

private int _maxResults; public int MaxReuslts {   get { return _maxResults++; }   set { _maxResults = value; } } 

See how the behavior would change if it in-lines your code?

If there's no logic...either method you wrote is fine, it's a very minute difference and all about how readable it is TO YOU (or your team)...you're the one looking at it.

like image 38
Nick Craver Avatar answered Sep 20 '22 21:09

Nick Craver