C# Optimizations Via Caching – Part 2

On March 22, 2009, in C#, Programming, by Akash Kava

I decided to write part 2 of optimization, with C# Project, to actually test the performance for accessing NameValueCollection and Property access.

I had lot of comments by extra smart people quoting regarding my previous post at "C# Optimizations Via Caching" . That all methods posted do not do any significant impact on performance, I wonder people just have habit of posting any thing without even thinking once.

So I decided to write a piece of code to actually demonstrate the optimization impact with statistics. In this Visual Studio 2008 C# Console Project, I wrote a simple code to access an application config value directly for 10,000 times in a loop and then to access it via statically cached variable. And in second part, I implemented accessing property and accessing a local variable nearly 10 million times to detect noticeable effect.

The tests are as follow,

Lets look at the test code to access config values, also please note that config values are stored in NameValueCollection, which is same object used in Request, Response and Session objects in web request.

// Configuration Access Test
Console.WriteLine("Testing Direct Config Access");

Test(1000000, () => {
     string v = System.Configuration.ConfigurationManager.AppSettings["Key"];
});

Console.WriteLine("Testing Cached Access");
Test(1000000, () => {
     string v = SettingVal;
});

Following is the result, on Intel Centrino Duo with 1GB of RAM, this shows that the code with cached access in static variable is 100 times faster.

Testing Direct Config Access

Time Difference 1125 MilSecs

Testing Cached Access

Time Difference 15.625 MilSecs

So now next time you code, remember it to not access frequently in loops.

Lets talk about property access,

// Property in Loop Test
int pc = 10000000;
Console.WriteLine("Testing Direct Property Access");
Test(() => {
    Person p1 = new Person();
    for (int i = 0; i < pc; i++)
    {
        string v = p1.Name;
    }
});

Console.WriteLine("Testing Local Variable Access");
Test(() => {
    Person p1 = new Person();
    string t = p1.Name;
    for (int i = 0; i < pc; i++)
    {
        string v = t;
    }
});

In order to detect any noticeable difference, we have to loop for about 10 million times, however, in any usual code, you will be accessing 100s of properties, so it may make a good difference when you write code, which executes million times parallel.

Testing Direct Property Access

Time Difference 140.625 MilSecs

Testing Local Variable Access

Time Difference 46.875 MilSecs

Now based on the amount of free memory, and cpu speed, you might have to configure the number of iterations up and down to get a good noticeable effect of two different ways.

I can clearly see the difference, remember on normal piece of code, you will be accessing over 10 to 100s of properties again and again.

Click on Caching Stats Visual Studio Project to download and test by yourself.

Share
Tagged with:  

C# Optimizations Via Caching

On December 12, 2008, in C#, by Akash Kava

Being computer science expert, I can visualize the load on Processor when I write the code, and though its cumbersome sometime to write more code to perform optimized operation,but its real worth while to spend time to understand Caching in programming.

Static Caching Config Values

The configuration values that you probably store in some config file, or some xml, or some registry etc should be statically cached in any class. For example, you need to access "AppConnectionString" defined in web.config or app.config, if you use expression

WebConfigurationManager.ConnectionStrings["AppConnectionString"]

every time then it would be very costly as first it tries to get instance of config file, then the section and then once again the HashTable of probably NamedValueCollection type and so on. This all is very costly for any value that is stored in config file and which stays unchanged for months or even years. I would always access it in a static class like this.

private static string _AppConnectionString = null;
public static string AppConnectionString
{
    if(_AppConnectionString == null)
    {
        _AppConnectionString =
            WebConfigurationManager
             .ConnectionStrings["AppConnectionString"]
             .ConnectionString;
    }
    return _AppConnectionString;
}

Property Cache in Local Variable

Consider following code

void DrawEffectRectangle(Rectangle r)
{
   for(int i=50; i>=0;i--)
   {
      SetColor(i*5);
      Draw3dRect(r.Left - i, r.Top - i, r.Right + i, r.Bottom + i);
   }
}

This method uses 4 properties, Left, Top, Right and Bottom, now consider following effective code which produces exactly same effect.

void DrawEffectRectangle(Rectangle r)
{
   int left = r.Left;
   int top = r.Top;
   int bottom = r.Bottom;
   int right = r.Right;
   for(int i=50; i>=0;i--)
   {
      SetColor(i*5);
      Draw3dRect(left - i, top - i, right + i, bottom + i);
   }
}

Now note, the calls to property evaluation has been reduced, lets assume one property access code takes 1ms then this code will execute 446ms times faster then the earlier code.

Note, you should use this technique carefully after examining that the value of these property evaluations are constant throughout the execution.

Cache Before Loop

Assuming following code,

for(int i=0;i<Results.Length;i++)
{
   ProcessResult(Results[i]);
}

Now here as well, expression i<Results.Length gets evaluated Results.Length times, assuming it to be an array. But consider the following code,

int len = Results.Length;
for(int i=0;i<len;i++)
{
   ProcessResult(Results[i]);
}

Caching once again the Length in a local variable reduces Property Evaluation code.

QueryString Caching

Most of the time, we have habbit of using ‘Request.QueryString["SomeID"]‘ this is very bad if you keep on calling this way, you must cache this in beginning of Page processing that will significantly improve your Web Server Performance. I would use following way to initialize my QueryString based Page variables.

private T GetQueryStringValue<T>(string name, T def)
{
   object val = Request.QueryString[name];
   if(val == null)
      return def;
   return (T)Converter.ChangeType(typeof(T),val);
}

private long CustomerID = 0;
private string Process = "";

private void Page_Load(object sender, EventArgs e)
{
   CustomerID = GetQueryStringValue<long>("CustomerID", 0);
   Process = GetQueryStringValue<string>("Process", "Signup");
}

And then using the values of CustomerID and Process variables rather then accessing Request.QueryString object again and again. There are two advantages in it, first, you can avoid Request.QueryString calls, and second you can compare native type comparisons to evaluate your algorithm flow. And you can see yourself after decompiling Request object through Reflector, that each access of Request.QueryString and its indexer basically requires more then 20-80 steps to get final result. Sure processor has 3 GHz but that doesnt mean that 1000 requests can just waste so many cpu cycles and finally frustrating the end user who is waiting expecting some result !!

Session Variable Caching

I would also try to cache, session variable in local page class as defined following,

private long _SessionWebUserID = -1;
private long SessionWebUserID{
   get{
      if(_SessionWebUserID == -1)
      {
         _SessionWebUserID = 0;
         object val = Session["WebUserID"];
         if(val != null)
         {
            _SessionWebUserID = (long)val;
         }
      }
      return _SessionWebUserID;
   }
}

Sure this method has additional _SessionWebUserID != -1 comparison everytime you access the property, but belive me, its far less costly then accessing Session NamedValueCollection again and again.

However the drawback is, if you cache session variable for longer period then its life in static variable, if it changes outside in session, you will never know. Thats why I always keep it as instance property instead of static, so I assume that atleast for this instance of page, the session value is constant.

Avoid Property of Property Style

Consider following code,

string url = HttpContext.Current.Request.Url;
string method = HttpContext.Current.Request.Method;

Both method has HttpContext.Current.Request as common code, and it actually has 2 Property Evaluation codes. Considering simple property evaluation execution time is 1ms, above code finishes in 6ms.

Ideally such code should be written as,

HttpRequest request = HttpContext.Current.Request;
string url = request.Url;
string method = request.Method;

Now this rewritten code finishes in 4ms, as first statement executes two property evaluation code to get final useful HttpRequest object.

Caching Method Results

Sure all of above methods even apply to method results too, as Property evaluation is just an internal get_Property method.

Result

Ok fine, I do the caching but how it improves performance? The answer is quite simple, each of above discussed methods requires numerous Property evaluation, Hashtable eveluation code, in order to read certain values. Now accessing local stack variable or static variable is many times faster then accessing property as it is a new method to access some other variable or some calculated variable. The indexed or hashed properties take even more time as the search is dependent upon the number of items present in the list or dictionary. Each such operation may execute few millsecond faster then before, but the overall performance increases with many concurrent execution. Not only CPU cycles but memory usage also can be improved as less method calls, less stack in use and less overhead on memory.

Oh such big lecture just for avoiding Property Evaluations? Well yes, remember Property Evaluation code is nothing but a simple method execution for CPU. And inside the .NET CLR environment, CPU needs to do a lot before an actual code is executed. Please note, this is assumed hypothetical Call sequence, the actual .NET CLR call sequence can be much more complex.

  1. Access target object (in which property exists)
  2. Access internal "Get" method handle for this target object’s type
  3. Allocate the Stack
  4. Do some book keeping, note the pointer values for tracking Exception StackTrace
  5. Setup local variables if any
  6. Move to the pointer of first instruction
  7. Evaluate expressions and actual code (for NamedValueCollection this could be quite long)
  8. Push result on stack
  9. Finish the Call
  10. Pop the result
  11. Unwind stack and do some book keeping to unwind Exception StackTrace

So, you can see, CPU needs to do a lot just before it can give you property evaluation result. And in case of Cached value in local variable, this can simply reduce in one or two instructions for subsequent frequent access.

Memory Usage

Using more such cached variables doesnt increase memory overhead? Well significantly not, because you are not going to have million such variables in one single threaded execution, most of these variables will be reused from time to time. Each local cached variable in method execution is on stack, and it only takes one space unit, however executing actual property again and again will even require more stack usage.

This isn’t same as External Caching

Sure web servers are written with great deal of effort and do provide good caching mechanism. Even ASP.NET has various caching methods, but those caching things are for very generalized purpose, the methods I am detecting here is not supposed to be misunderstood with the page, control caching. Because even other caching methods requires at least first time complete processing in order to get the results. Also these are pure processor level execution improvements, it has nothing to do with where your application is executing, it can be your web server code or your mobile app code or even database assembly code.

Share
Tagged with: