How to Optimize your Application using Visual Studio Profiler

This post shows you How to optimize your app using Visual Studio Profiler.

Sometimes some of the methods you write are slow, but you don't know where the problem is. This is when you need a code analysis tool.

Through this article, you will learn how to run code analysis in Visual Studio, as well as use the Visual Studio Profiler to optimize your programming code.

It is a dynamic program analysis tool to identify performance issues like, memory, complexity of program time, CPU usage, etc.

C# code analyzers

Creating a console application, then create a simple method as show below.

public static void TestWriteFileToDisk(int numberOfRecord)
{
    for (int i = 1; i <= numberOfRecord; i++)
    {
        using (SqlConnection cn = new SqlConnection(ConfigurationManager.ConnectionStrings["cn"].ConnectionString))
        {
            if (cn.State == System.Data.ConnectionState.Closed)
                cn.Open();
            using (SqlCommand cmd = new SqlCommand($"select ProductName from Products where ProductID={i}", cn))
            {
                using (SqlDataReader reader = cmd.ExecuteReader())
                {
                    if (reader.Read())
                        System.IO.File.AppendAllText($"{Application.StartupPath}\\data.txt", $"{i}: {reader.GetString(0)}\n");
                }
            }
        }
    }
}

Modifyding your App.config as shows below.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
    </startup>
  <connectionStrings>
    <add name="cn" connectionString="Data Source=.;Initial Catalog=Northwind;User ID=sa;[email protected];" providerName="System.Data.SqlClient"/>
  </connectionStrings>
</configuration>

I'm using Northwind database to play demo. The TestWriteFileToDisk is a simple method allows you to get data from product table in your Northwind database, then write it to file.

We will observe the code before and after being optimized.

Modifyding your Main method as shown below.

static void Main(string[] args)
{
    // Press Ctrl+F5 (or go to Debug > Start Without Debugging) to run your app.            
    TestWriteFileToDisk(77);
    Console.WriteLine("Finished !");
    Console.ReadKey();
}

How to run code analysis in Visual Studio 2017, 2019

Changing from Debug to Release mode, then select Analyze =>Performance Profiler

performance profiler

Clicking on Performance Wizard, then click the Start button.

visual studio performance wizard

Selecting Instrumentation.

visual studio performance wizard

Selecting One or more available projects.

visual studio performance wizard

Selecting your project, then click Next button.

visual studio performance wizard

Finally, Click Finish button.

When you see the word "Finished !" in the app, you turn off the app.

visual studio instrumentation profiling

You can see the CPU usage percentage in the graph above is always high.

visual studio instrumentation profiling

The AppendAllText method takes 42.73 percent.

Now we will optimize our code as follows.

public static void TestWriteFileToDisk(int numberOfRecord)
{
    string connectionString = ConfigurationManager.ConnectionStrings["cn"].ConnectionString;
    StringBuilder stringBuilder = new StringBuilder();
    for (int i = 1; i <= numberOfRecord; i++)
    {
        using (SqlConnection cn = new SqlConnection(connectionString))
        {
            if (cn.State == System.Data.ConnectionState.Closed)
                cn.Open();
            using (SqlCommand cmd = new SqlCommand($"select ProductName from Products where ProductID={i}", cn))
            {
                using (SqlDataReader reader = cmd.ExecuteReader())
                {
                    if (reader.Read())
                        stringBuilder.Append($"{i}: {reader.GetString(0)}\n");
                }
            }
        }
    }
    System.IO.File.AppendAllText($"{Application.StartupPath}\\data.txt", stringBuilder.ToString());
}

Moving the connection string out of the loop, using StringBuilder to concatenate text instead of writing directly to the file. Finally, We will convert the stringBuilder variable to String, then write it to file.

We will continue to reuse Visual Studio Profiler to optimize your code.

visual studio instrumentation profiling

As you can see in the graph above, we have reduced the execution time from 1.352 seconds to 0.205 seconds

visual studio instrumentation profiling

As you can see, AppendAllText method reduced to 4.84%

We will continue to re-optimize your code as follows.

public static void TestWriteFileToDisk(int numberOfRecord)
{
    string connectionString = ConfigurationManager.ConnectionStrings["cn"].ConnectionString;
    StringBuilder stringBuilder = new StringBuilder();
    for (int i = 1; i <= numberOfRecord; i++)
    {
        using (SqlConnection cn = new SqlConnection(connectionString))
        {
            if (cn.State == System.Data.ConnectionState.Closed)
                cn.Open();
            using (SqlCommand cmd = new SqlCommand($"select ProductName from Products where ProductID={i}", cn))
            {
                using (SqlDataReader reader = cmd.ExecuteReader())
                {
                    if (reader.Read())
                        stringBuilder.AppendFormat("{0}: {1}\n", i, reader.GetString(0));
                }
            }
        }
    }
    System.IO.File.AppendAllText($"{Application.StartupPath}\\data.txt", stringBuilder.ToString());
}

Using AppendFormat of StringBuilder instead of Append method.

visual studio instrumentation profiling