How to diagnostic slow code with Visual Studio
Posted on: 2016-03-23
During the development of one feature, I noticed the performance to be very slow in some scenario. It was not obvious at first because the task was to simply update a user profile. The user profile in question is stored in a single table. It's a pretty straight forward task. Before persisting the data, some validations are done but that is it.
This is where Visual Studio can be very useful with the integrated Diagnostic Tools
. The diagnostic tools provide information about event and on any of them, you can come back in time and replay the call stacks which is pretty useful. It also gives some timing information, cpu usage and memory usage. To start diagnosing, simply attach Visual Studio to the process you want to diagnostic. After, open Visual Studio's diagnostic tools that is located in the top menu under Debug > Profiler > Performance Explorer > Show Performance Explorer
.
Here is an example of the output that I got from my performance problem.
Visual Studio Diagnostic tools events include Entity Framework SQL statements. This is where I realized that the user's table was updated but also hundred of others which looks to be a table linked to this one. Here was the performance bottleneck, the culprit! I never expected to update anything related to that table -- just the main user's table.
Entity Framework code was like this:
public void Update(ApplicationUser applicationModel) {
//Update the password IF necessary
var local = UnitOfWork.Set<ApplicationUser>().Local.FirstOrDefault(f => f.Id == applicationModel.Id);
if (local != null) {
UnitOfWork.Entry(local).State = EntityState.Detached;
}
UnitOfWork.Entry(applicationModel).State = EntityState.Modified;
if (string.IsNullOrEmpty(applicationModel.PasswordHash)) {
UnitOfWork.Entry(applicationModel).Property(f => f.PasswordHash).IsModified = false;
}
UnitOfWork.Entry(applicationModel).Property(f => f.UserName).IsModified = false;
UnitOfWork.Entry(applicationModel).Property(f => f.CreationDateTime).IsModified = false;
UnitOfWork.Entry(applicationModel).Property(f => f.ValidationDateTime).IsModified = false;
UnitOfWork.Entry(applicationModel).Property(f => f.LastLogin).IsModified = false;
UnitOfWork.Entry(applicationModel).Property(f => f.SecurityStamp).IsModified = false;
UnitOfWork.Entry(applicationModel).Property(f => f.Language).IsModified = false;
}
As you can notice, nothing is done directly on the property that has the collection of "reputation". The problem is that if the user as in that collection 250 objects, that for an unknown reason, Entity Framework does 250 updates. Since we want just to update first name, last name and few other basic properties than we need to be sure to remove those unwanted updates. After some modification with Entity Framework, like nulling every collection before updating, The SQL provided was only a single SQL, whence the performance at full speed.