How can I verify if a function has been cached in C#? - c#

I have created the following functions in C#:
float GetPI()
{
return 22.0f/7.0f;
}
void Calculate()
{
float f1 = GetPI()*4;
float f2 = GetPI()*5;
}
If I create a release build, how will I be able to verify whether the JIT compiler will cache the 22/7 calculation, or whether it will be calculated each time the function GetPI is called?
PS : I do not have visual C# studio professional edition
EDIT : changed 22/7 to 22.0f/7.0f to make the example function more accurate

I'm not sure what you mean by being cached. Unless the compiler doesn't do any constant folding (which it will in this case) or the runtime doesn't inline your function (which it probably would in this case), it will not do any "caching" automatically for you.
The expression 22f/7f is a constant expression and can be evaluated at compile time (aka, constant folding). So in the compiled assembly, it will appear as:
float GetPI()
{
return 3.142857f; // however many digits of precision
}
The compiler will always make this kind of optimization if given the opportunity. Unless there's a compiler option to disable this (which I'm not sure there is). To verify this happens, you could use Reflector (as the others have pointed out) to see the compiled assembly. You should see that it does indeed do this whether it is Debug or Release builds or using the express versions (unless this optimization is explicitly disabled).
If the function is simple enough, the runtime might inline your function call. So rather than calling this function, it will insert the result in place of the function call. Seeing as this is just a function to just return some number, it will probably will do this optimization. I don't know if there even is a way to see if this happens without actually seeing the JIT compiled code through a debugger.
If you mean caching as in memoization, then no this will not be done automatically and you'll have to do this yourself.
If you want an absolute guarantee that the compiler will "cache" (as in not recalculate the quotient) the value, you should declare your value as a constant (or use the existing and more accurate System.Math.PI constant). Nothing is being determined at runtime, everything is known at compile time. And every time you use this value, it will be "inlined" so you won't have to worry about that.
const float PI = 22f / 7f; // will be stored as 3.142857f
// or another way, if you need PI to be a float but want a more accurate value
const float PI = (float)Math.PI; // will store as much precision possible
// note that this only works because Math.PI is declared as a constant

Download and install .NET Reflector (originally written by Lutz Roeder, and now maintained by Red Gate). You may have to look for an older version if you don't want to pay.
When you open your code in Reflector, you can see what changes the compiler made.
This wouldn't show you JIT optimizations, you need to step through the machine code in a debugger for that, but I'm pretty sure this case will be evaluated by the C# compiler.

There are many ways. One convenient is using .NET Reflector.
Open up your assembly in Reflector, select C#, find the method in the treeview, select Tools/Disassemble. The disassembler will show something like the following:
public float GetPI()
{
return 3f;
}

Related

C# assignment in constructor to member ... doesn't change it

I have a simple class intended to store scaled integral values
using member variables "scaled_value" (long) with a "scale_factor".
I have a constructor that fills a new class instance with a decimal
value (although I think the value type is irrelevant).
Assignment to the "scaled_value" slot appears... to not happen.
I've inserted an explicit assignment of the constant 1 to it.
The Debug.Assert below fails... and scaled_value is zero.
On the assertion break in the immediate window I can inspect/set using assignment/inspect "scale_factor"; it changes as I set it.
I can inspect "scaled_value". It is always zero. I can type an
assignment to it which the immediate window executes, but its value
doesn't change.
I'm using Visual Studio 2017 with C# 2017.
What is magic about this slot?
public class ScaledLong : Base // handles scaled-by-power-of-ten long numbers
// intended to support equivalent of fast decimal arithmetic while hiding scale factors from user
{
public long scaled_value; // up to log10_MaxLong digits of decimal precision
public sbyte scale_factor; // power of ten representing location of decimal point range -21..+21. Set by constructor AND NEVER CHANGED.
public byte byte_size; // holds size of value in underlying memory array
string format_string;
<other constructors with same arguments except last value type>
public ScaledLong(sbyte sf, byte size, string format, decimal initial_value)
{
scale_factor = sf;
byte_size = size;
format_string = format;
decimal temp;
sbyte exponent;
{ // rip exponent out of decimal value leaving behind an integer;
_decimal_structure.value = initial_value;
exponent = (sbyte)_decimal_structure.Exponent;
_decimal_structure.Exponent = 0; // now decimal value is integral
temp = _decimal_structure.value;
}
sbyte sfDelta = (sbyte)(sf - exponent);
if (sfDelta >= 0)
{ // sfDelta > 0
this.scaled_value = 1;
Debug.Assert(scaled_value == 1);
scaled_value = (long)Math.Truncate(temp * DecimalTenToPower[sfDelta]);
}
else
{
temp = Math.Truncate(temp / DecimalHalfTenToPower[-sfDelta]);
temp += (temp % 2); /// this can overflow for value at very top of range, not worth fixing; note: this works for both + and- numbers (?)
scaled_value = (long)(temp / 2); // final result
}
}
The biggest puzzles often have the stupidest foundations. This one is a lesson in unintended side effects.
I found this by thinking about, wondering how in earth a member can get modified in unexpected ways. I found the solution before I read #mjwills comment, but he was definitely sniffing at the right thing.
What I left out (of course!) was that I had just coded a ToString() method for the class... that wasn't debugged. Why did I leave it out? Because it obviously can't affect anything so it can't be part of the problem.
Bzzzzt! it used the member variable as a scratchpad and zeroed it (there's the side effect); that was obviously unintended.
When this means is that when code the just runs, ToString() isn't called and the member variable DOES get modified correctly. (I even had unit tests for the "Set" routine checked all that and they were working).
But, when you are debugging.... the debugger can (and did in this case) show local variables. To do that, it will apparently call ToString() to get a nice displayable value. So the act of single stepping caused ToSTring() to get called, and its buggy scratch variable assignment zeroed out the slot after each step call.
So it wasn't a setter that bit me. It was arguably a getter. (Where is FORTRAN's PURE keyword when you need it?)
Einstein hated spooky actions at a distance. Programmers hate spooky side effects at a distance.
One wonders a bit at the idea of the debugger calling ToString() on a class, whose constructor hasn't finished. What assertions about the state of the class can ToString trust, given the constructor isn't done? I think the MS debugger should be fixed. With that, I would have spent my time debugging ToString instead of chasing this.
Thanks for putting up with my question. It got me to the answer.
If you still have a copy of that old/buggy code it would be interesting to try to build it under VS 2019 and Rider (hopefully the latest, 2022.1.1 at this point) with ReSharper (built in) allowed to do the picky scan and with a .ruleset allowed to bitch about just about anything (just for the 1st build - you'll turn off a lot but you need it to scream in order to see what to turn off). And with .NET 5.0 or 6.0
The reason I mention is that I remember some MS bragging about doing dataflow analysis to some degree in 2019 and I did see Rider complaining about some "unsafe assignments". If the old code is long lost - never mind.
CTOR-wise, if CTOR hasn't finished yet, we all know that the object "doesn't exist" yet and has invalid state, but to circumvent that, C# uses default values for everything. When you see code with constant assignments at the point of definition of data members that look trivial and pointless - the reason for that is that a lot of people do remember C++ and don't trust implicit defaults - just in case :-)
There is a 2-phase/round initialization sequence with 2 CTOR-s and implicit initializations in-between. Not widely documented (so that people with weak hearts don't use it :-) but completely deterministic and thread-safe (hidden fuses everywhere). Just for the sake of it's stability you never-ever want to have a call to any method before the 2 round is done (plain CTOR done still doesn't mean fully constructed object and any method invocation from the outside may trigger the 2nd round prematurely).
1st (plain) CTOR can be used in implicit initializations before the 2nd runs => you can control the (implicit) ordering, just have to be careful and step through it in debugger.
Oh and .ToString normally shouldn't be defined at all - on purpose :-) It's de-facto intrinsic => compiler can take it's liberties with it. Plus, if you define it, pretty soon you'll be obliged to support (and process) format specifiers.
I used to define ToJson (before big libs came to fore) to provide, let's say a controllable printable (which can also go over the wire and is 10-100 times faster than deserialization). These days VS debugger has a collection of "visualizers" and an option to tell debugger to use it or not (when it's off then it will jerk ToString's chain if it sees it.
Also, it's good to have dotPeek (or actual Reflector, owned by Redgate these days) with "find source code" turned off. Then you see the real generated code which is sometimes glorious (String is intrinsic and compiler goes a few extra miles to optimize its operations) and sometimes ugly (async/await - total faker, inefficient and flat out dangerous - how do you say "deadlock" in C# :-) - not kidding) but you need to to be able to see the final code or you are driving blind.

Decimal variable overwritten in watch window

I noticed that the parameter a evaluates to diff in the watch window (even if b is non-zero), when breaking on the return statement line, which doesn't make sense to me. If uncommenting the line above, that doesn't happen. Any ideas? Do you guys get the same result? I used Visual Studio Ultimate 2013 12.0.40629.00 Update 5, debug build.
public decimal Subtract(decimal a, decimal b)
{
var diff = a - b;
//var test = a;
return diff;
}
since this is probably a compiler issue
Depends on your definition of "issue". What you see is not unexpected if you are debugging an optimized build. The C# compiler is unlikely to coalesce variable storage (I'm guessing it simply can't), but the JIT compiler, which is what creates the native code that actually executes, certainly can and most likely would.
So, your variable a, being unused after the assignment to diff, is having its storage location reused for the variable diff, rather than allocating a whole new location for it.
Since both variables are using the same location, when you watch the value in the debugger, changing one variable has the effect of changing the other.
For more discussion on debugging optimized builds, see:
Cannot obtain value because it has been optimized away
What is the point of nop in CIL
The second link doesn't really pertain to the "reused variable slot" aspect per se, but Hans' answer does include the sentence "You can still debug a Release build, it is however a pretty confounding experience that makes you doubt your sanity", which IMHO sums up the whole broad topic nicely. :)

Why use const (or Readonly)?

While I understand the function of these 2 keywords, I do not understand why do we use them.
I did a lot of research but most of my findings only talk about WHAT and WHEN to use const or readonly or the difference between each, but none of them explain WHY. Let's take the example below:
const decimal pi = 3.142
decimal circumference = 2 * pi * //r
as opposed to
decimal pi = 3.142
decimal circumference = 2 * pi * //r
The purpose of const/readonly is to prevent people from changing the value, but it is not like the user has the chance to change the value of decimal pi, so why bother using const (or readonly)?
Please note: My question is WHY do we use const/readonly, but NOT "what are const/readonly.
Additional info: I need to clarify this one more time. I don't think the question is under-researched. I clearly understand the functionality of each keywords, but I just don't know why do we even bother using them. Does it actually improve performance? Or it's just a "decorative" way to emphasize: Hey - please don't change me?
Compiler optimizations and to tell fellow Developers that they shouldn't be modified.
"Readonly" is an expression of your intention as a programmer, and a safeguard. It makes your life easier (and anyone who has to maintain your code in the future) if a read-only constraint can be enforced. For example, if you have a "readonly" member that is initialized in the constructor, you will never have to check it for a null reference.
"Const" is similar in that its value cannot be changed, but also quite different in that its value is applied at compile time. This makes it more memory-efficient, as no memory needs to be allocated for "const" values at runtime. Note however that, in contrast to "readonly", "const" only supports value types -- "const" reference types are not allowed.
There is one interesting implication of the difference between "readonly" and "const", when writing class libraries. If you use a "const", then any applications that use your library must be re-compiled if you distribute a new version of the library with a different value for the "const". By contrast, if you use a "readonly" member, then applications will pick up a modified value without needing to be re-compiled (as you can imagine, this would simplify your life if you had to distribute a patch or hotfix).
Its not for the user of your program. It is for other programmers. It makes it abundantly clear that this value should not be changed. Pi should never change. It may seem a bit silly in your small example but when projects span thousands of lines of code and get split into functions it can be different.
Also that value could get passed into a reference with a different name. How does the programmer know that it should not be changed any more? Perhaps he gets it with the keyword calculationValue he thinks will I wouldnt mind changing this to 50.0 for my uses. Next thing he knows he changed the value of pi for tons of other methods.
There are a few reasons. The first would be if the variable would be accessible by outside code, you wouldn't want someone else changing the definition of PI, also it makes it clear that this variable should never change, which does provide the ability for the compiler to make some optimizations. Then there's also the fact that it can prevent you from making a mistake in your own code and accidentally changing a constant value.
It's not only about the user but also about the developer I would say. Half a year and 20,000 lines of code later you - or anyone else working on the code - might have simply forgotten about this.
Plus, could be performance improvements when using constants I would assume
Two reasons:
Indicating to other developers that this is a value that should never change. It can help to distinguish between values like pi (which will always be 3.1415...), versus values that may some day be based on a configuration, or a user's input, or some other situational condition.
Along the same lines, you can help to prevent other developers doing something stupid like trying to assign a new value to the pi variable, because the compiler will yell at them. In a simple two-line method like this, that's less likely to be an issue, but as your code base grows more complex it can save people a lot of time to be prevented from doing things they're not supposed to do.
Allowing compilers to make optimizations. Both the initial compilation and the JIT compilation can take advantage of information about values that you know are not going to change. In the example you've given, the compiler will generate the equivalent of the following code when you use the const keyword:
decimal circumference = 6.284m * r;
Notice how the CPU doesn't need to multiple 2 * pi every time you call the method, because that's a value which is known at compile-time.

Code is behaving differently in Release vs Debug Mode

We have some unit tests that fail when run in Release mode vs debug mode. If I attach a debugger in release mode the tests pass. There is way too much code to publish here so I am really just looking for best practices in debugging Release mode issues. I have checked for:
DEBUG and RELEASE preprocessor directives but I did not find any.
Conditional Methods
SOLUTION: In this case it is because I was comparing floating point variables for equality. I could not change the floats to decimal without a major refactoring so I added an extension method:
public static class FloatExtension
{
public static bool AlmostEquals(this float f1, float f2, float precision)
{
return (Math.Abs(f1 - f2) <= precision);
}
public static bool AlmostEquals(this float f1, float f2)
{
return AlmostEquals(f1, f2, .00001f);
}
public static bool AlmostEquals(this float? f1, float? f2)
{
if (f1.HasValue && f2.HasValue)
{
return AlmostEquals(f1.Value, f2.Value);
}
else if (f1 == null && f2 == null)
{
return true;
}
return false;
}
}
One thing that might cause the behaviour that you are seeing is an error that causes a race condition. Attaching a debugger can change the timing of the code such that the race condition is no longer triggered.
To fix it, use synchronization appropriately whenever you have multiple threads accessing data.
I am comparing some float values in the IsEqual method.
That sounds like a very bad idea. You should not compare floats for equality because floating point calcualtions are not 100% precise and you can get representation and rounding errors. Compare to see whether they are sufficiently close together. For calculations involving money, you probably want to use the decimal type instead.
Since it seems to be floating point related there are so many things that can go wrong. See:
C# - Inconsistent math operation result on 32-bit and 64-bit
and
Double precision problems on .NET
There are so many things that can be trashed with floating points. And comparing floats for equality is a general no-no. You chould check the difference smaller than a reasonably epsilon.
Questions you should ask yourself -
Is my code threaded? Timing differences will affect output
Is someone calling Debug.Assert() with an expression that side effects?
What objects implement IDisposable() and do some do so in such a way that changes state?
Are you P/Invoking into unmanaged code?
Number 3 is a very likely bad-boy in this case. Garbage collection may be very different in debug and release and you may find that when an object is garbage collected is affecting the outcome of a later unit test.
And FYI, if you're using NUnit and TestDriven.NET - the two run tests in different orders.
This is often the case as the debug build is not optimized by default, and even if you enable it, the behavior when debugging is very different. You can disable the "Optimize code" from the project settings for all assemblies on the Properties->Build tab.
There are certainly other changes that can cause differences, like you mention Conditional Methods are one. These I've found to rarely be the cause of issues, for me it's almost always the optimizer.
Classic gotcha's of the optimizer include methods that get 'inlined' so that they fail to appear on a call stack. This causes problems when using System.Diagnostics.StackFrame classes to determine the current execution point. Similarly this will affect the result of MethodBase.GetCurrentMethod or other functions/behavior that rely on the executing method.
Then there are of course many things I've seen the optimizer do that I simply cannot explain at all. One such example was documented and discussed in a post 'HashDerivedBytes - replacing Rfc2898DeriveBytes, but why?' but I've never solved the mystery. I only know that the optimizer just flat broke Rfc2898DeriveBytes when used to generate a series of derived bytes. Oddly enough this only broke when the bytes generated were not evenly divisible by the size of the hash algorithm used (20) and only produced incorrect results after the first 20 bytes.
The fact is that optimizations adversely affecting code is not a new thing for compilers. Most of the old-school C++ developers will tell you that straight away and then, as I did, go into some long drawn out story about how they worked around it ;)
As Mark suggests, this is usually a result of a timing-related issue, often a race condition or synchronization problem.
One common way to handle this sort of problem is to use "print" statements in the affected areas to show you what's going on. If the print statements (Console.WriteLine, Response.Write, logging, or whatever) make the problem go away, store the values in global variables and print the globals once the problem has shown up.
The most recent time this has happened to me was in code that was reading from a serial port. The debugging activity caused just enough of a change in timing to affect how bytes from the serial port were buffered, which changed how the buffer was getting parsed. Since the print statements changed the timing, I had to store the data up to output later.
Just to add my two cents to this, I recently found that I had a date comparison in an sql procedure that the testing called. The dates were all auto-generated prior in the test procedure and values were inserted into the DB, and so occasionally they were exactly the same (when using RunTests) causing a null to be returned on a table join. Not what I was expecting. Obviously, in debug mode, since I'm slowly progressing through it, there will be a difference in the auto-generated times which meant that I never bumped into the error. I resolved this by inserting
Threading.Thread.Sleep(520)
wherever there would definitely be a delay between actions. Problem fixed.

Is it possible to check values at compilation?

Is it possible in C# to have some sort of check list when compiling to ensure parameters to functions are certain values?
For example, can I check that the parameter of this function is always greater than 10 at compile time?
void SomeFunction(1); <--- Compile error here
Take a look at Code Contracts. It's quite powerful; it can be used for both runtime checking and static verification. In addition, you can configure it to treat unproven contracts as compile-time warnings / errors.
void SomeFunction(int number)
{
Contract.Requires<ArgumentOutOfRangeException>(number > 10)
...
}
I don't know of any way to do this at compile time, you may be better off using an enumeration and only providing values in that enumeration that are above 10.
But, of course, this limits you to specific values which may not be what you want.
There are other options available to you such as:
runtime error, like throwing an exception.
runtime ignore, such as an if statement that exits the function for values that aren't in your range.
At a pinch, you could process the source code with another executable which examines values passed into you function, but that will only work for calls that can be bolied down to a constant argument. And, if they're constant arguments, you will catch them at runtime during the testing phase, long before your product gets within a hundred feet of a customer or beta tester. Unless your testing coverage is not up to scratch but then that's a different problem.
Otherwise, runtime checking is your only option.
If it isn't a very simple program I think this is impossible. It sounds related to the Halting problem.

Categories

Resources