Profiling Apps 1 of N: The MVC ActionLink

 

I’m starting a new series of blogs posts on profiling, where we’ll try and cover common bottlenecks and how to identify them in your applications. However, before delving deeper into the subject, let me make a small but important observation:

Your bottleneck is probably not your for loop

Now, replace that for loop with switch statement, an older version of some outdated algorithm that you feel needs optimizing, or that retched collection of classes that would perform better if you were using an array to loop through them, and you’ll end up with the same observation.

Premature Optimization

When dealing with business applications, it is unusual for major performance problems to be pinpointed down to specific portions of code or a concrete implementation of an algorithm. Usually most of the issues are bottlenecks at the data level, network level or purely down to how a business decision is made.

Whether we use an ORM or use SQL directly, incorrectly formulated queries are one of the most predominant causes of bad performance. Not understanding concepts such as Lazy or Eager loading when using an ORM can be disastrous to the performance of an application, and are usually portrayed as “ORM XYZ sucks at performance”. 

Network bandwidth and latency are other issues; when dealing with web applications for instance, having large pages (i.e. ViewState) or rendering Javascript directly without using script files, are a common problem for performance penalties. Making heavy calls to the server when very little information is required (i.e. UpdatePanel used incorrectly) are again main causes for concern.

In many cases, design decisions we make early can affect the performance of our applications, and it is important to identify these concerns and address them correctly. Using an ORM, profiling it, understanding how Ajax really works and not worrying about working with Javascript, or using an asynchronous architecture when dealing with long running business processes are many ways to avoid bad performance in the long run.

On the other hand, what we shouldn’t do is focus on micro-optimizations, on trying to make the most efficient, yet completely undecipherable algorithm to calculate the probability of winning money when buying lottery tickets, when the underlying problem is a bottleneck caused by a bad query. This kind of approach is often referred to as Premature Optimization, and can be disastrous for a project.

When it does boil down to code

Having said all that, there are times when we need better performance after having eliminated all the obvious causes, and need to discover why something is not performing as well as it should be. Of course, these concerns are greater when the nature of our application demands highly optimized code. In these cases, it is crucial to understand how things work in order to solve the problem. As a old-school boy, before we had managed libraries and drag-n-drop, I’m also a firm believer that it is always important to understand how things work under the covers, even if it is to just improve one self's knowledge.

Therefore, in these series of blog posts about performance, I’m going to focus on the latter, examining the details of code and how some things can perform better than others. So given the disclaimer, let’s get down to business.

In order to do performance tuning, you need to use a tool. Setting stopwatches doesn’t work, because as Christian Gross so rightly pointed out during one of his talks, and I semi-quote: ‘if you’re using a stopwatch, you think you know where the bottleneck is. Most of the time, you’re wrong’.  If you are setting using a manual approach of setting calling Start and Stop, trying to time something, you’re assuming you know that the performance problem is located in a particular point, and many times it is not that point. So you end up having to place these kind of diagnostic codes in various places in your code, and soon it becomes a maintenance nightmare. Fortunately, there are tools that can profile your application in a non-invasive manner. When talking about SQL profiling, there’s NHProfiler for instance. When it comes to code performance profiling, the two most known ones are ANT Profiler and dotTrace. I’m going to be using dotTrace. I used it before joining JetBrains and continue to use it now that I’m at JetBrains. I’ll be using version 4.0 which is currently (at the time of writing this post), in Early Access Program and with Beta being released very soon.

To Express or not Express

Those that are familiar with it ASP.NET MVC know it relies heavily on the use of strings in many areas. For instance, when defining ActionLinks, you write

Html.ActionLink(“Home”, “Index”, “Home”)

where the first parameter is the link text, the second the Action and the third parameter is the Controller. The problem with this of course is that if you type either the second or third parameter incorrectly, you won’t know until runtime. Even if you build your views it won’t help.

An alternative is to use Expression based Html Helpers (another option is to use ReSharper of course :)). These are strongly-typed ActionLinks that do not ship out of the box with ASP.NET MVC, but are available as a separate download in the MVC Futures assembly, which can be thought of as a kind of sandbox for Microsoft to play with. Some of the functionalities in this library have eventually made it to the main core, such as RenderPartial, which was in fact there from pretty much the early Previews of MVC 1, and didn’t get all the excitement until it made it into the core in version 2. Other functionality, including the expression based ActionLinks haven’t made it in yet. When using these helpers, the previous link would be:

Html.ActionLink<HomeController>( a => a.Index, “Home”)

In principle this looks good, and begs the question of why it is not in the main core. Well I don’t know the exact reason, but one could potentially be due to it’s performance. Several people have talked about the difference in terms of rendering when using this version as opposed to the standard string based one. You can find one of those posts here. What I thought I’d do, is actually see how much difference in speed there is between one and the other.

The Project

I’m using a very simple project for this profiling. It’s your standard ASP.NET MVC 2 application. On Index page, I’ve added two blocks of code:

  1. <% for (int i = 0; i < 1000; i++)
  2. {%>
  3.   <%= Html.ActionLink("Link " + i, "Index", "Home")%><br />
  4.   <%
  5. } %>
  6.  
  7. <% for (int i = 0; i < 1000; i++)
  8. {%>
  9.   <%= Html.ActionLink<HomeController>(a => a.Index(), "Link " + i)%><br />
  10.   <%
  11. } %>

The first for loop will render out 1000 links using the string based ActionLink version, whereas the second loop will do the same using the expression-based one.

What we want to do now is run this and see how long it takes for each loop to complete.

Setting up dotTrace Profiler

Working with dotTrace is as easy as it gets. There are two ways to profile an application: Standalone or integrated within Visual Studio. In the case of the former, you can start up dotTrace outside of Visual Studio and point to an application to profile. On the other hand if you have it integrated inside Visual Studio, then all you need to do is click on the Profile menu option:

image

Once we do that, we get a dialog box that provides us a series of options, mainly to do with the type of profiling we are going to perform.

image

Since we’re profiling a web application, we can either use the Development Server or Internet Information Server. In our case we’re going to use the former. dotTrace will automatically pick up the server settings as well as fill out the physical path for our application.

Next come the profiling options. The basic settings are Profiling Type and Meter Kind. The first parameter indicates how profiling will take place. It can be:

  • Sampling: dotTrace will do frequent analysis of calls stacks. It’s the least intrusive, has very little impact on performance, but gives approximate timing.
  • Tracing: dotTrace receives notifications from the CLR on entry/exit of methods. More precise timing and call information.
  • Line-by-Line: dotTrace logs times for every statement in methods. Most precise but also has higher impact on performance.

Tracing is normally the recommended option. Meter Kind defines how dotTrace logs the time: CPU instruction or Performance counter (uses the Windows API and samples are hardware independent).

Profiling our application

Once we have everything setup, we can start profiling our app. dotTrace will launch a small panel that allows us to control data sampling.

image

dotTrace does not by default however launch the browser. In order to do so, we need to either click on the WebDev server and Open in Browser or just type the URL directly in the browser.

image

The next step is to perform the operations we want to profile and then click on GetSnapshot.

image

Since in our case, having rendered the Index action performs these operations, once the page has been loaded, we can click on GetSnapshot and have the profiler launched.

image

I’m not going to get into all of the details of dotTrace in this first post because otherwise it would never end;  we’ll cover some of the aspects in future posts. For now, lets focus on our performance test at hand which is the difference between the two types of ActionLinks (string and expression based).

The easiest way to find what we are looking for is to use the…you guessed it, Find feature. Ctrl+F will bring up a dialog box similar to ReSharper’s Type location. We can then type ActionLink to filter the list of functions down to the ones that interest us

image

We can see that there are two versions, as expected. Let’s drill in to the second one first, the string based one. Hitting Enter will find the first location. We can then press F3 until we find the one that interests us. Remember, Site.Master and other references to this call also exist. We’re specifically looking for the loop, the one with 1000 calls

image

We can see that the ActionLink call takes 121ms for 1000 calls. Drilling in, we can see exactly where the time is spent, and 104ms of that is calling GenerateUrl. Now let’s take a look at the Expression based ActionLink

image

For the same 1000 calls it takes 140ms, which is an increase of approximately 17%. Diving in once again, we can see that 6ms of this is in the parsing of the expression tree, GetRouteValuesFromExpression. What this function does is merely analyze the expression to extract the ActionName from the parameter. The ControllerName it already has since it’s the concrete type the generic method is invoked with, returning both values in a RouteValueDictionary. As such it then needs to call GenerateRouteLink as opposed to GenerateLink since the former takes a RouteValueDictionary as a parameter, whereas the latter takes strings indicating the controller and action. They ultimately both call GenerateUrl.

Summary

From the results, the difference between the two calls is not that significant for 1000 links. As the number of links increment, the difference between the two does not change significantly. For instance, rendering 10.000 links, has a difference of 50ms between one version and another. What’s interesting that having run the same profiling on previous releases, the difference in time was nearly double, so there seems to have been improvement in this area. And as we can see, sometimes what might seem a performance problem, isn't necessarily one.


Posted 03-09-2010 9:34 PM by Hadi Hariri
Filed under: , ,

[Advertisement]

Comments

Paco wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 03-09-2010 5:16 PM

You don't have a performance problem when method a is slower than method b, but you have a performance problem when your application is too slow to agree with your SLA. When you have a webpage with a lot of links (count the links on this page), I can imagine situations where 100ms is significant. When your SLA says that 100ms is fine, you don't have to worry, even when 99 of that 100ms are involved in generating links. It is a reason to be curious to start the profiler, but it is not a performance problem.

When you want to compare two approaches of doing something, you have to realize you just compare it in the context where you use it. The two ways of generating links are almost equally fast in your situation, but that doesn't mean that there is no significant difference in every situation. When you really want to compare the two approaches, you should create a chart with all involved parameters, and show which approach is the fastest in which situation.

I once had a performance problem with generating links in mvc. I opened reflector, and saw that the largest difference of generating the links with the 2 approaches in my situation was caused by RouteCollection.GetVirualPath. With some link generating methods, all routes would be enumerated here, and with some there would be a look up on routename. The application I was working had a few hundreds of views and about 100-200 routes. The difference was much larger than the difference in your situation, something like 2 whole seconds vs some milliseconds for 1000 links. I solved the problem by creating my own strongly typed version of the actionlink method.

There is no performance problem when the app is not to slow.

There is no context in a benchmark to compare two methods, but there is a context in profiling an application.

Hadi Hariri wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 03-10-2010 1:46 AM

@Paco,

The point with covering ActionLinks and comparing the two were to see what the real difference is between them. Many times one has been discarded in favour of other for performance reasons, whereas that performance difference might not even be a real issue.

Obviously context is important.

9eFish wrote Profiling Apps 1 of N: The MVC ActionLink - Hadi Hariri - Devlicio.us - Just the Tasty Bits
on 03-10-2010 10:43 AM

9efish.感谢你的文章 - Trackback from 9eFish

Tim Barcz wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 03-10-2010 11:57 PM

Hadi,

This was a great read, thanks for sharing.

One thought for future performance topics (one that's been on my mind) is the RenderAction versus RenderPartial in the MVC framework since the two operate differently.

Thanks again,

Tim

Steve wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 03-11-2010 7:27 AM

There was quite a large a difference in performance between the two ActionLink helpers in MVC 1, but the v2 MvcFutures adds a lot of caching which from your measurements obviously improves performance *a lot*.

I think that now the main reason they haven't rolled this into the main release of v2 is the lack of support for Areas which is currently flagged as "Wont Fix" on CodePlex:

aspnet.codeplex.com/.../View.aspx

Because of this the expression-based helpers appear to be pretty much useless for any marginally-complex MVC2 project.

Simon wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 03-11-2010 11:02 AM

"Html.ActionLink<HomeController>( a => a.Index, “Home”)

In principle this looks good, and begs the question of why it is not in the main core. Well I don’t know the exact reason, but one could potentially be due to it’s performance. "

Another reason they might not have wanted the expression based syntax is that it breaks the usage of the ActionName attribute as detailed <a href="blogs.lessthandot.com/.../a>

Hadi Hariri wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 03-11-2010 11:50 AM

@Simon,

Page not found...but if it breaks that, then that just a bug no?

uberVU - social comments wrote Social comments and analytics for this post
on 03-12-2010 6:36 PM

This post was mentioned on Twitter by sbgservices: Profiling Apps 1 of N: The MVC ActionLink - Hadi Hariri - Devlicio ...: Usually most of the issues are bottlene.. http://bit.ly/c8ofUG

Paco wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 03-13-2010 2:47 PM

@Steve: I just browsed the MVC2 futures source code, but I didn't found the caching. What kind of caching do you mean?

I looked at LinkExtensions, LinkBuilder and ExpressionHelper.

Steve wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 03-16-2010 12:49 PM

@Paco Check out the CachedExpressionCompiler class in Microsoft.Web.Mvc.ExpressionUtil

Paco wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 03-16-2010 6:58 PM

@Steve: Thanks for the information about the CachedExpressionCompiler class. It doesn't seem to be in the current codeplex sourcecode. Did they remove it for some reason? I found the code somewhere else, and it looks very interesting, and usable for various expression caching purposes. Do you know why the code is removed from the current codeplex repository?

Steve wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 03-17-2010 12:26 PM

@Paco The source I'm referring to comes from the MVC Futures download here: aspnet.codeplex.com/.../41742

I've no idea if the actual Source from the "Source Code" tab on CodePlex is the current version or not, but from what you're saying it sounds like it's not.

social bookmarking submit wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 01-17-2013 10:40 PM

OzjeJF Really appreciate you sharing this blog post.Really looking forward to read more. Will read on...

loss weight pills wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 02-01-2013 11:09 AM

BSxYLh I am so grateful for your article. Really Great.

buy viagra wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 02-03-2013 10:43 AM

xJOXPS I really like and appreciate your blog article.Really looking forward to read more. Great.

buy viagra online wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 02-03-2013 1:22 PM

Y7SUKO Thank you ever so for you post.Thanks Again. Fantastic.

generic clomid wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 02-25-2013 5:08 AM

FVIL4g I really enjoy the blog post.Thanks Again. Really Cool.

buy clomid no prescription wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 02-28-2013 1:00 PM

PpEueh I truly appreciate this blog post.Much thanks again. Really Great.

buy clomid no prescription wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 03-01-2013 1:59 AM

dvckHP I really like and appreciate your blog.Really looking forward to read more.

buy viagra online wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 03-02-2013 3:53 PM

xyNJCt Wow, great blog article.Thanks Again. Cool.

buy discount viagra wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 03-03-2013 8:59 PM

AO3qPL Thank you for your article post. Awesome.

bookmarks wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 03-13-2013 4:15 PM

hckMI7 I cannot thank you enough for the post.Much thanks again. Really Great.

social bookmarks wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 03-13-2013 7:26 PM

S9nujG I value the blog article.Really thank you! Will read on...

Social bookmarks wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 03-22-2013 7:24 PM

Qtgor6 Muchos Gracias for your blog post.Thanks Again. Much obliged.

buy social bookmarks wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 03-23-2013 12:22 AM

UQAt68 Enjoyed every bit of your article post.Thanks Again.

Social bookmarks wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 04-03-2013 2:00 PM

nzPgDZ Very informative article.Much thanks again. Great.

buy social bookmarks wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 04-04-2013 12:39 AM

IeGRDh I truly appreciate this blog post.Thanks Again. Really Cool.

comedy wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 04-05-2013 6:43 PM

Very good post.Really looking forward to read more. Want more.

stoners wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 04-06-2013 1:25 AM

Thanks-a-mundo for the article.Really thank you! Want more.

social bookmarking service wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 04-07-2013 10:34 PM

RgcFIH Awesome blog post.Thanks Again. Awesome.

digital slr lenses wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 05-14-2013 10:42 AM

G5Efgw Hey, thanks for the blog.Thanks Again. Really Great.

cheap social bookmarks wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 06-19-2013 2:17 PM

dePsWo Enjoyed every bit of your post.Really looking forward to read more. Fantastic.

news and many more wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 07-04-2013 12:34 PM

pb9ZKx I truly appreciate this blog.Really looking forward to read more. Really Cool.

hot news wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 07-26-2013 10:31 AM

J9hp0P Major thanks for the article post.Really looking forward to read more. Much obliged.

greatest news wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 08-03-2013 8:58 AM

zO6KTC wow, awesome blog post.Really thank you! Will read on...

super news that are fun wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 08-04-2013 4:32 PM

kyMx4G I really enjoy the blog.Really thank you! Awesome.

great link buildng wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 08-19-2013 12:16 PM

AiFjCl Awesome blog post.Really looking forward to read more. Much obliged.

awesome links for you wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 08-19-2013 11:58 PM

pC44zz Really appreciate you sharing this post.Thanks Again.

good seo guys wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 09-04-2013 2:05 AM

2u49Ig I appreciate you sharing this blog post.Thanks Again. Really Cool.

make money online wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 09-11-2013 7:17 PM

qMidYN Very good post.Much thanks again. Great.

cheap link building wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 09-24-2013 6:56 PM

vIGbsC Thank you for your blog article.Thanks Again. Fantastic.

link building team wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 09-30-2013 10:19 PM

U9a0iU Really enjoyed this blog article.Much thanks again. Want more.

best link build wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 10-16-2013 10:59 AM

KjRJqs Great, thanks for sharing this post.Much thanks again. Keep writing.

top seo guys wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 10-25-2013 7:13 PM

TchBgL I appreciate you sharing this article post.Really looking forward to read more. Really Cool.

take a look at it! wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 10-31-2013 4:04 AM

RNqBBj Thanks so much for the post.Much thanks again. Awesome.

check this out wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 11-20-2013 8:44 AM

JEkd3b Fantastic article. Fantastic.

check this out wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 12-15-2013 5:37 AM

lJRg8q This is one awesome blog article.Thanks Again. Cool.

awesome things! wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 01-08-2014 7:26 AM

OmD689 Thanks for sharing, this is a fantastic blog. Really Great.

nice seo guys wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 01-15-2014 11:41 PM

Tuac9N A big thank you for your article.Really looking forward to read more.

best prices wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 03-22-2014 7:34 AM

Kb5X5j A big thank you for your article post.Thanks Again. Keep writing.

check it out wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 04-01-2014 10:34 AM

eQFzN8 Thanks for sharing, this is a fantastic article post.Thanks Again. Great.

check this out now wrote re: Profiling Apps 1 of N: The MVC ActionLink
on 04-05-2014 1:23 PM

QC9oR4 Im thankful for the article.Really thank you! Really Cool.

Add a Comment

(required)  
(optional)
(required)  
Remember Me?

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)