Sunday 28 February 2016

Benchmark - the correct tool

[BenchMark] is fantastic. It keeps the boilerplate code to capture the important process level metric abstracted away from you and lets you focus on writing useful application level flow tests that are important to you and business. And using it is as simple as adding an attribute on the function that you wish to benchmark and asking the benchmarkrunner to take care of rest of the stuff. I tried it out with some old code blocks.

First and most important thing is that you have to write less code :)

public class TypeA
    {
        public string Name { get; set; }
        public string Value { get; set; }
        [Benchmark]
        public static void MeasureJsonSerializationPerformance()
        {
            var obj = new TypeA() { Name = "Name", Value = "Value" };
            string[] jsonStrings = new string[1];
            string jsonString1 = Newtonsoft.Json.JsonConvert.SerializeObject(obj);
            jsonStrings[0] = jsonString1;
        }
        [Benchmark]
        public static void MeasureBsonSerializationPerformance()
        {
            var obj = new TypeA() { Name = "Name", Value = "Value" };
            string[] bsonStrings = new string[1];
            MemoryStream ms = new MemoryStream();
            using (BsonWriter writer = new BsonWriter(ms))
            {
                JsonSerializer serializer = new JsonSerializer();
                serializer.Serialize(writer, obj);
            }
            string bsonString1 = Convert.ToBase64String(ms.ToArray());
            bsonStrings[0] = bsonString1;
        }
}

That is pretty much all I needed to write as my test bed. Now all I need to do is to call this:

BenchmarkRunner.Run();

There you have it. Benchmark takes care of many of the low level nuances that you would otherwise not be thinking of when writing your own performance testing console app. The performance results show up in a nice window:

// * Summary *
BenchmarkDotNet=v0.9.1.0
OS=Microsoft Windows NT 6.2.9200.0
Processor=Intel(R) Core(TM) i7-3740QM CPU @ 2.70GHz, ProcessorCount=8
Frequency=2628190 ticks, Resolution=380.4900 ns
HostCLR=MS.NET 4.0.30319.42000, Arch=32-bit RELEASE
Type=TypeA  Mode=Throughput
                              Method |        Median |     StdDev |
------------------------------------ |-------------- |----------- |
 MeasureBsonSerializationPerformance | 1,651.0726 ns | 11.7229 ns |
 MeasureJsonSerializationPerformance |   857.5405 ns | 12.1060 ns |
// ***** BenchmarkRunner: End *****

Tuesday 16 February 2016

Async/Await - avoid misuse

Since the introduction of async/await constructs in C#/VB languages for .NET runtime, it has become more and more popular. I know a lot of folks who have switched to using async/await instead of any of the old asynchronous programming patterns. 


However, there are few common pitfalls. E.g.

1. Developers get carried away with the usage of await keyword and ConfigureAwait function and therefore they end up using it in places where it is actually not required. For example -

private async Task GetValueFromStore(string key)
{
            string val = this.cache[key];
            if(val != null)
            {
                return await Task.FromResult(val).ConfigureAwait(false);
            }
            else
            {
                val = await GetFromDBAsync(key).ConfigureAwait(false);
                //insert into cache
                return await Task.FromResult(val).ConfigureAwait(false);
            }
}



In the above example, Task.FromResult are unnecessary. It could have been simply:

private async Task GetValueFromStore(string key)
{
            string val = this.cache[key];
            if(val != null)
            {
                return val;
            }
            else
            {
                val = await GetFromDBAsync(key).ConfigureAwait(false);
                //insert into cache
                return val;
            }
}



Updated method saves unnecessary creation of Task objects on heap (btw, Task.FromResult sets the status to RanToCompletion at the time of creation and is not queued on thread pool). Check discussion about Task.FromResult.


2. Sometimes folks use the elegant chain of asyn/await in the control flow till they hit a roadblock and simply change the last block to use Result property of Task to make it run immediately (and on calling thread) in blocking manner. That is bad - it gives false hope that flow will be run using async/await constructs.

One such scenario is to run multiple SQL queries inside a transaction. Till .NET 4.5 there was no support for async tasks inside TransactionScope and therefore developers used code blocks like following:

[HttpGet]
public async Task DbQuery()
{
            using (TransactionScope s = new TransactionScope())
            {
                var result = await ExecuteStoredProcedure("usp_Procedure1", null).ConfigureAwait(false);
                //result = -1;
                var result2 = await ExecuteStoredProcedure("usp_Procedure2", result).ConfigureAwait(false);
                s.Complete();
            }
            return new ContentResult() { Content = "SP run done", ContentType = "text/html" };
}
          
private async Task ExecuteStoredProcedure(string spName, int? val)
{
            using (SqlConnection conn = new SqlConnection("Server=.;Initial Catalog=Test;Integrated Security=SSPI;"))
            {
                SqlCommand command = new SqlCommand();
                command.Connection = conn;
                command.CommandText = spName;
                command.CommandType = System.Data.CommandType.StoredProcedure;
                if (val.HasValue)
                {
                    command.Parameters.Add(new SqlParameter("Table1Id", val.Value));
                }
                conn.Open();
                using (var reader = command.ExecuteReaderAsync().Result)
                {
                    if (reader.Read())
                    {
                        return Convert.ToInt32(reader["Identity"]);
                    }
                }
            }
            return -1;
}

This issue was fixed in .NET 4.5.1. So, instead of getting stuck with above code, you can change to:

[HttpGet]
public async Task DbQuery()
{
            using (TransactionScope s = new TransactionScope(TransactionScopeAsyncFlowOption.Enabled))
            {
                var result = await ExecuteStoredProcedure("usp_Procedure1", null).ConfigureAwait(false);
                //result = -1;
                var result2 = await ExecuteStoredProcedure("usp_Procedure2", result).ConfigureAwait(false);

                s.Complete();
            }

            return new ContentResult() { Content = "SP run done", ContentType = "text/html" };
}


private async Task ExecuteStoredProcedure(string spName, int? val)
{
            using (SqlConnection conn = new SqlConnection("Server=.;Initial Catalog=Test;Integrated Security=SSPI;"))
            {
                SqlCommand command = new SqlCommand();
                command.Connection = conn;
                command.CommandText = spName;
                command.CommandType = System.Data.CommandType.StoredProcedure;
                if (val.HasValue)
                {
                    command.Parameters.Add(new SqlParameter("Table1Id", val.Value));
                }

                conn.Open();
                using (var reader = await command.ExecuteReaderAsync().ConfigureAwait(false))
                {
                    if (reader.Read())
                    {
                        return Convert.ToInt32(reader["Identity"]);
                    }
                }
            }

            return -1;
}


I am sure that there would be some other scenarios like the above one where you may be forced to run the code blocks in single thread in blocking manner. However, there are workarounds too. For example - you can use Task.Run or use TaskCompletionSource in certain scenarios to make it favorable. The bottom line is to verify if the scenario is indeed not possible and if it is not then do not forget to remove Async/Await from upstream code blocks too to reduce false impressions.

Sunday 14 February 2016

Checked keyword

Here comes another typical issue - this time it is related to date values. If you ever wondered why date starts at 1/1/1970 in some systems/applications, below video can provide you some idea about the reason. And, you also get to know that if you are not counting properly you would run into either integer overflow issue or integer underflow issue.

Btw, .NET has support to handle overflow scenarios. Refer unchecked and checked keywords in C#. It is rather less popular amongst developers because .NET runtime puts in plenty of checks and balances to ensure you are not turning into your enemy.



Check out other videos by Tom Scott. He is fantastic.