Friday, June 28, 2013

Don't aim for success (2013-06-28)

Don't aim for success if you want it; just do what you love and believe in, and it will come naturally.

- David Frost

Want to Understand Mortality? Look to the Chimps (nytimes.com)

Pansy was probably in her 50s when she died, which is pretty good for a chimpanzee. She passed in a way most of us would envy — peacefully, with her adult daughter, Rosie, and her best friend, Blossom, by her side. Thirty years earlier, Pansy and Blossom arrived together at the Blair Drummond Safari and Adventure Park near Stirling, Scotland. They raised their children together. Now, as Pansy struggled to breathe, Blossom held her hand and stroked it.

Read more...

Wednesday, June 26, 2013

Lesson learned in refactoring ASP.NET MVC3 routes

What's the problem, Doc?

Typical ASP.NET MVC applications will not face performance issues related to routing. General applications will have one default route ({controller}/{action}/{id}) and several custom ones. Our own custom-built CMS catches all non-custom routes. Therefore, we added a separate and distinct route for every action. You can say that our application is not a typical one – it has a large number of custom routes (approximately 300). Why do a large number of routes lead to performance issues? Let’s find out.

Always do profiling before refactoring

Some time ago, we noticed that one of our client’s websites was getting slower. Because of this, we started investigating performance issues. The site has rather heavy client-side JavaScript logic, so we assumed that we needed to tweak our JavaScript code. However, before jumping into JavaScript optimization, we wanted to make sure that our assumption was correct. Therefore, we started profiling our web application. The results were rather surprising. The performance issue was related to server-side logic. Response time from the server was 2 to 3 seconds, even without any back-end logic. 2 to 3 seconds just to render a simple page without any content on it! After a few hours of intensive profiling, debugging, and head scratching, we finally isolated the source of the problem. Performance issues were somehow related to the MVC routing table. Profiling results showed that a large portion of CPU time was used by MVC routing methods. The profiler showed that the GetVirtualPath method in the RouteCollection class was called one hundred times while rendering one page.

Look into the sources, Luke

Last year, Microsoft released the source code of ASP.NET MVC3 to the public. We downloaded the ASP.NET MVC 3 source code and started analyzing it. The GetVirtualPath method contains a loop that iterates through all configured routes and finds the first one that returns a match. Here is the source of the GetVirtualPath method:

public VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values) {
    requestContext = GetRequestContext(requestContext); 

    // Go through all the configured routes and find the first one that returns a match 
    using (GetReadLock()) { 
        foreach (RouteBase route in this) {
            VirtualPathData vpd = route.GetVirtualPath(requestContext, values); 
            if (vpd != null) {
                vpd.VirtualPath = GetUrlWithApplicationPath(requestContext, vpd.VirtualPath);
                return vpd;
            }
        }
    }
    return null;
} 

This code fragment traverses all routes in the route table to find a match. When the route table grows, the time it takes to find a match grows as well. We also searched the MVC3 source code to find places where the GetVirtualPath method was referenced. This method was used in many other places, like in common Html helpers. Here is the path from Html.ActionLink to GetVirtualPath.

LinkExtenions.cs ActionLink => HtmlHelper.cs GenerateLink => HtmlHelper.cs GenerateLinkInternal => UrlHelper.cs GenerateUrl => RouteCollection.cs GetVirtualPathForArea => RouteCollection.cs GetVirtualPath

When the number of custom routes increases, your web application starts to get slower. If you use Html helpers like ActionLink, response time increases even more. Every call to ActionLink executes the same loop in the GetVirtualPath method. The GetVirtualPath method can be executed one hundred times for one request if you use many Html helpers. Response time is also affected by the place of matched route in the routing table. The closer the route is to the beginning of the table, the quicker the match is found, and the quicker the GetVirtualPath loop terminates itself.

Give me some numbers...

I have created a simple MVC application to emulate route-related performance issues. In its essence, this application is identical to Microsoft’s VisualStudio MVC template. I have only added custom routes into the Global.asax file as needed.

public static void RegisterRoutes(RouteCollection routes)
{
  routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
  
  routes.MapRoute("browse-1", "browse/test1", new { controller = "Home", action = "Test1" });
  routes.MapRoute("browse-2", "browse/test2", new { controller = "Home", action = "Test2" });
  routes.MapRoute("browse-3", "browse/test3", new { controller = "Home", action = "Test3" });
  routes.MapRoute("browse-4", "browse/test4", new { controller = "Home", action = "Test4" });
  routes.MapRoute("browse-5", "browse/test5", new { controller = "Home", action = "Test5" });
  routes.MapRoute("browse-6", "browse/test6", new { controller = "Home", action = "Test6" });
  routes.MapRoute("browse-7", "browse/test7", new { controller = "Home", action = "Test7" });
  routes.MapRoute("browse-8", "browse/test8", new { controller = "Home", action = "Test8" });
  routes.MapRoute("browse-9", "browse/test9", new { controller = "Home", action = "Test9" });
  routes.MapRoute("browse-10", "browse/test10", new { controller = "Home", action = "Test10" });

//Add more custom routes here as needed

  routes.MapRoute("support", "support", new { controller = "Home", action = "Support" });
  routes.MapRoute("documentation", "documentation", new { controller = "Home", action = "Documentation" });
  routes.MapRoute("how-to", "how-to", new { controller = "Home", action = "HowTo" });
  routes.MapRoute("get-started", "get-started", new { controller = "Home", action = "GetStarted" });
  routes.MapRoute("about", "about", new { controller = "Home", action = "About" });

  // Default route
  routes.MapRoute("Default", "{controller}/{action}/{id}", new { controller = "Home", action = "Index", id = UrlParameter.Optional });
}

I have also modified the Views/Home/Index.cshtml file and have added calls to ActionLink to it.

@{
    ViewBag.Title = "Home Page";
}

@ViewBag.Message

To learn more about ASP.NET MVC visit http://asp.net/mvc.

  • @Html.ActionLink("Home/Test1", "Test1", "Home")
  • @Html.ActionLink("Home/Test2", "Test2", "Home")
  • @Html.ActionLink("Home/Test3", "Test3", "Home")
  • @Html.ActionLink("Home/Test4", "Test4", "Home")
  • @Html.ActionLink("Home/Test5", "Test5", "Home")
  • @Html.ActionLink("Home/Test6", "Test6", "Home")
  • @Html.ActionLink("Home/Test7", "Test7", "Home")
  • @Html.ActionLink("Home/Test8", "Test8", "Home")
  • @Html.ActionLink("Home/Test9", "Test9", "Home")
  • @Html.ActionLink("Home/Test10", "Test10", "Home")

In the first test, I added custom routes to the routing table to see how this affects response times. I have recreated a worst-case scenario: the matched route is at the end of the routing table. I have started from 5 routes and increased the number of routes by 10 for each subsequent iteration. In the last run, there were 100 routes in the routing table. In the second test, I also added calls to @Html.ActionLink helper into the index view. This is a mixed scenario, because the matched route is at the end of the routing table, but the ActionLinks in the index view points to every route in the routing table. I used the same number of routes in the routing table and helpers in the index view. I started from 5 routes and increased the number of routes by 10 for each subsequent iteration. In the last run, there were 100 custom routes in the routing table and 100 helpers in the index view.

Test setup

All tests were performed on my development machine. The test application was built in release mode and hosted on IIS server to emulate the production environment. I used Apache jMeter to generate some traffic to the test site. Here is the jMeter configuration I used for testing:

I started with the first test scenario with 5 custom routes. I ran the test five times with 5 routes and took an average value of response times. After that, I added 10 more custom routes and repeated my previous actions. For the last test in the first scenario, I ran the test with 100 custom routes in the routing table. I did the same with the second test scenario afterwards.

Test results

The graph below shows results for the first test scenario. The X axis shows the number of custom routes in the routing table. The Y axis shows response time.

The graph below shows results for the second test scenario. The X axis shows the number of custom routes in the routing table and calls to ActionLink helper. The Y axis shows response time.

The graph shows that the number of calls to ActionLink helpers also increases response time. If you have a simple page with 100 ActionLinks and a route table with 100 custom routes, the response time is almost 2 seconds. Keep in mind that this simple application has no back-end logic and only 100 links, while the response time is ~2seconds!

What can you do about it?

The most important rule – keep your route table as small as possible and use the default route as much as possible.

Find the most used routes and move them into the beginning of the routing table. This way, you will ensure that the GetVirtualPath method loop will find a match and terminate itself as soon as possible.

Find custom routes that are not visible to the user or not important for backward compatibility and remove them from the routing table.

This post is also crossposted in DevBridge Blog

WebGL, SPDY/3, New Dev Tools, & More Confirmed For IE11 In Win 8.1 (microsoft-news.com)

Microsoft released Windows Server (“Blue”) to MSDN subscribers today, ahead of the BUILD (#bldwin) conference later this week in San Francisco. The build provides us a number of clues as to what we will see in the official Windows 8.1 (Blue) preview. The server build number is 9341, the windows 8.1 preview build will be: 6.3.9431.winmain_bluemp.130615-1214. IE11 scores 351/500 + 2 bonus point, and 25/25 for WebGL. Since this is a server build, the score may be a little higher than IE11 on Win 8.1, but this confirms WebGL for IE11. IE11 WebGL Conformance Test Results: 14,748 of 20,509 tests pass (71.9%). Many things seen in the Server 2012 R2 preview will also show up in the Windows 8.1 preview.

Read more...

Thursday, June 20, 2013

The real reason to fight nuclear power has nothing to do with health risks (qz.com)

Missing from the entire debate about nuclear is the most important fact of all: Nuclear is dying due to poor economics, and the debate is already over as far as the market is concerned.

Read more...

Wednesday, June 19, 2013

Prominent Scientists Sign Declaration that Animals have Conscious Awareness, Just Like Us (ieet.org)

An international group of prominent scientists has signed The Cambridge Declaration of Consciousness in which they are proclaiming their support for the idea that animals are conscious and aware to the degree that humans are — a list of animals that includes all mammals, birds, and even the octopus.

Read more...

Containers—Not Virtual Machines—Are the Future Cloud (linuxjournal.com)

Cloud infrastructure providers like Amazon Web Service sell virtual machines. EC2 revenue is expected to surpass $1B in revenue this year. That's a lot of VMs.

It's not hard to see why there is such demand. You get the ability to scale up or down, guaranteed computational resources, security isolation and API access for provisioning it all, without any of the overhead of managing physical servers.

But, you are also paying for lot of increasingly avoidable overhead in the form of running a full-blown operating system image for each virtual machine. This approach has become an unnecessarily heavyweight solution to the underlying question of how to best run applications in the cloud.

Read more...

Friday, June 14, 2013

Don’t Hash Secrets (benlog.com)

So here it is: Don’t hash secrets. Never. No, sorry, I know you think your case is special but it’s not. No. Stop it. Just don’t do it. You’re making the cryptographers cry.

What the heck am I talking about, you say? I’ll explain. But before we get lost in the details, just remember. Don’t hash secrets. Ever. Kapish?

Read more...

Wednesday, June 12, 2013

Better CMS for Developers (bettercms.com)

Better CMS is a publishing-focused and developer-friendly .NET Open Source CMS developed by DevBridge Group. The first official public release version is available, and there is a demo website to see it in action. Try it yourself!

Read more...

Monday, June 10, 2013

Understanding Express.js (http://evanhahn.com)

Express.js describes itself better than I can: "a minimal and flexible node.js web application framework". It helps you build web apps. If you've used Sinatra in the Ruby world, a lot of this will be familiar.

Read more...

Wednesday, June 5, 2013

Ten LINQ Myths (albahari.com)

Here are ten root causes of the most common misunderstandings—distilled from many hundreds of questions on the LINQ forums.

Read more...

Tuesday, June 4, 2013

Some things I've learnt about public speaking (jgc.org)

In the past I've written a couple of blog posts titled Some things I've learnt about programming and Some things I've learnt about writing. People seem to have enjoyed those posts (judging by the page view counts and comments) and so I thought I'd write something about public speaking and specifically about conference speaking.

Read more...