MiniProfiler 2.0, almost out of the gate
almost 13 years ago
Nine months ago I blogged about our MiniProfiler open source project. I used some hyperbole in the announcement blog. I goaded others to port MiniProfiler to their favourite web stack and accused us of living in the “stone age” of web profiling.
MiniProfiler attracted many lovers and some haters who either hated my marketing hyperbole speak or said that “real” profilers do not make you litter your code with superfluous profiling code. I responded with some helpers that allow you to automatically instrument your web apps. MiniProfiler does not prescribe profiling blocks, you can get very rich instrumentation with minimal changes to your code.
Exaggeration aside, awesome is infectious. PHP now has a port of MiniProfiler, Python has a port of MiniProfiler.
What problem is Mini Profiler Solving?
The main goal has always been, increase developer awareness around performance bottlenecks. Instead of simply “feeling” that a page “may” be slow. MiniProfiler tells you why it is slow. It is in your face telling you to remove the suck from your code.
With this in mind we made a few great evolutionary improvements to Mini Profiler.
Front end performance analysis
In 1968 Robert Miller wrote:
[Regarding] response to request for next page … Delays of longer than 1 second will seem intrusive on the continuity of thought
This was still true in the canonical Jacob Nielsen article 30 year later, it is still true today. We strive to have 100ms response time… everywhere.
However, the pesky speed of light thing keeps on getting in the way as does the stateless nature of the web.
As developers we often think that we only have control over performance problems in the server room, or equipment we own. The harsh reality is that the largest amount of pain is introduced in the front end, often the largest bang for buck is improving the front end.
MiniProfiler now allows you to measure your front end performance. This is accomplished by using Navigation Timings API. It is supported on Chrome, Firefox and IE9 (notably Opera and Safari are missing support for these APIs)
Additionally, you can add your own client side probes to measure the impact of your JavaScript includes and CSS. This allows you to easily share this information with your team, without needing fancy screen shots.
To add client side probes in an ASP.NET MVC app you would amend your master layout like this:
@using StackExchange.Profiling;
....
<head>
@this.InitClientTimings();
@this.TimeScript("jQuery",
@<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>)
The following will insert a simple JavaScript probe framework into your page and wrap your includes with it.
<script type="text/javascript">mPt=function(){var t=[];return{t:t,probe:function(n){t.push({d:new Date(),n:n})}}}()</script>
<script type="text/javascript">mPt.probe('jQuery')</script>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">mPt.probe('jQuery')</script>
Take this trace, for example, here is an initial request to the meta home page:
Here is a repeat request:
We may have a false sense of security thinking that our page only took 13 or so ms server side. My actual perceived user performance was waiting a long time before I saw anything. For the first case I waited 1.5 seconds before the CSS was evaluated. For a repeat view I waited 423ms till the CSS finished evaluating and the page even started rendering.
Tools like firebug, chrome dev tools or IE dev tools do not clearly report these times:
Looking at the screenshot from chrome we may think, incorrectly, that putting this script in the header had no impact. Note that speed tracer does show these timings and more, however, is not ubiquitous.
So, what can you do with this kind of information?
- You can invest time in pushing scripts to the footer and perhaps loading them async.
- You can start building a case for getting a CDN or a better CDN.
- You can look at minimizing scripts, CSS includes and trimming them down.
- You can easily share this information with your team, without needing to take awkward screen shots - you simply share a link.
- You can start thinking about crazy things, like replicating your database globally and serving pages from the closest location.
- And so on.
UI less profiling
In the past when MiniProfiler was on, the UI was always there. This is perfect for developers but makes it impossible to gather information about requests that are not coming from developers.
You can now enable profiling on any page in a UI-less mode. To do so, simply render your MiniProfiler include and start a session.
To start a session use the same API you did in the past:
In your Global.asax.cs file:
// Tell MiniProfiler if the current request can see the UI.
void Application_Start(object sender, EventArgs e)
{
MiniProfiler.Settings.Results_Authorize = httpRequest => IsUserAllowedToSeeMiniProfilerUI(httpRequest);
}
protected void Application_BeginRequest()
{
if (wouldLikeToGatherProfilingInfoAboutThisRequest)
{
profiler = MiniProfiler.Start();
}
}
protected void Application_EndRequest()
{
MiniProfiler.Stop();
}
The last thing in your master layout:
@if (wouldLikeToGatherProfilingInfoAboutThisRequest) {
@MiniProfiler.RenderIncludes()
}
Experimental list everything UI
We added a simple UI to list the recent 100 sessions. This allows you to view session you did not participate in and have no links to. The UI, we are accepting patches to spruce it up.
You can view it by going to http://your-sites/mini-profiler-resources/results-index
This UI is not enabled by default. You will need to “allow” users to see it:
MiniProfiler.Settings.Results_List_Authorize = (request) =>
{
// you may implement this if you need to restrict visibility of profiling lists on a per request basis
return true; // all requests are kosher
};
Script re-organisation
MiniProfiler always used jquery.tmpl for client side rendering. This plugin was “bolted on” to the current jQuery object. The trouble was that sometimes people decided to bolt on their own templating plugins and we stepped on each others feet.
The new version of MiniProfiler ships a stand alone version of jQuery and jquery.tmpl that are used in a .noCoflict()
mode. This mean you can have whatever version of jQuery you wish and it will not conflict with MiniProfiler.
Defer everything
In the past we expected MiniProfiler to be included in the header of the page, the new design encourages you to place MiniProfiler.RenderIncludes()
in your footer (if you don’t it will still attempt to load async). This means that we can accurately measure client side timings without interfering with your page render.
No longer MVCMiniProfiler
From launch we always allowed profiling of Web Forms and ASP.NET MVC apps. Mark Young submitted patches for improving EF support and added WCF support. Yet all projects where stuck importing an awkward namespace called MVCMiniProfiler. For the 2.0 release we shuffled around all the assembly names to use the StackExchange.Profiling
namespace. This sends a better message to the community about the purpose of the MiniProfiler project.
When upgrading you need to replace:
using MVCMiniProfiler
With
using StackExchange.Profiling
Other changes
Results_Authorize
used to take in a MiniProfiler object, now it does not.- MiniProfiler.EF now has a special method for initializing profiling for EF 4.2
Initialize_EF42
StackExchange.Profiling.Storage.IStorage
has a newList
that is used to query data in the list mode
Where Do I get it?
We uploaded MiniProfiler
, MiniProfiler.EF
and MiniProfiler.MVC
to nuget. While we are finalizing the 2.0 release you will need to install it from the Package Manager Console:
edit MiniProfiler 2.0 has now been released
PM> Install-Package MiniProfiler
A call to action
MiniProfiler has no website, MiniProfiler could have better documentation, MiniProfiler has not been ported to Ruby-on-Rails, Django, Lift or whatever other awesome web framework you may be using.
Contact me if:
- You would like to help built a site for MiniProfiler or get it a domain.
- You would like pointers porting it to your web framework
- You would like to take ownership of the MiniProfiler.WCF package (which is missing from nuget)
If there are any bugs you discover please report them here: Google Code Archive - Long-term storage for Google Code Project Hosting.
If you would like to help improve our documentation edit our little tag wiki and make it awesome.
Patches are always welcome, personally I prefer getting them on github.
Big thanks to Jarrod who designed much of the MiniProfiler internals and the community at large for the patches and support that got us to a 2.0 release.
Sam, Can someone tell me the difference between the various Nuget packages? i.e. MiniProfiler, MiniProfiler.EF, and MiniProfiler.MVC.