Poor man’s performance profiling

If you have been doing development with Xamarin on Android you have probably noticed the total absence of any profiler, there is not even a decent method to get the high resolution time. Sure, there is Environment.TickCount but the resolution is at best in milliseconds. Pretty useless for performance profiling.

Rarely people use performance profilers on the desktop. Mostly because their applications don’t have complicated stuff and the modern CPUs are hiding most of the non performing code. However mobile devices are far more delicate and have less CPU power, less RAM, less resources in general. Thus slow code is much more notable and visible to end users. There is no better way to profile your code with a performance profiler. Just take a look at RedGate’s ANTS Performance profiler. Unfortunately there are no such tools for Xamarin Android platform even though mobile code should be really optimized.

I present  my solution for getting some useable metrics from your code (the code you have sources for). The code I’ve written was used for MvvmCross performance profiling hence it slightly relies on it (logging, IoC) however it can be easily made standalone if necessary.

Getting high resolution time

Java has java.lang.System.nanoTime() method that returns the highest resolution time available on Android. Xamarin doesn’t provide it through .net, you have to write a wrapper by yourself using java reflection.

public static class JavaLangSystem
{
    static IntPtr class_ref;
    static IntPtr id_nanoTime;
    public readonly static long Avg;

    static JavaLangSystem()
    {
        class_ref = JNIEnv.FindClass("java/lang/System");
        id_nanoTime = JNIEnv.GetStaticMethodID(class_ref, "nanoTime", "()J");

        for (int i = 0; i < 10; i++)
        {
            NanoTime();
        }

        long start = NanoTime();
        for (int i = 0; i < 1000; i++)
        {
            NanoTime();
        }
        Avg = (NanoTime() - start) / 1000;
MvxTrace.TaggedTrace("metrics", "Avg NanoTime reflection is {0}", Avg); } [Register("nanoTime", "()J", "")] public static long NanoTime() { return JNIEnv.CallStaticLongMethod(class_ref, id_nanoTime); } }

Note that I do some calibration in static constructor because of reflection the call to nanoTime() itself consumes some time. I store the average call time into a static variable Avg that I'll later use.

Accessing high resolution timer through IoC

First part is to create an interface

public interface IHighResolution
{
    long Ticks { get; }
    long Avg { get; }
}

then implement it

public class HighResolution: IHighResolution
{

    #region IHighResolution Members

    public long Ticks
    {
        get { return JavaLangSystem.NanoTime(); }
    }

    public long Avg
    {
        get { return JavaLangSystem.Avg; }
    }

    #endregion
}

and finally register it to IoC provider.

protected override IMvxApplication CreateApp()
{
    Mvx.RegisterType<IHighResolution, HighResolution>();
    return new App();
}

I register it in MvxAndroidSetup derived class (MvvmCross initialization) but if you are not using MvvmCross feel free to register it with IoC provider of your choice on some other initialization place.

This separation comes specially handy if you are to measure PCL assemblies where nanoTime() isn’t accessible.

 

Define class that will store a single measurement

[DebuggerDisplay("{Name} in {Ticks}")]
public class PerfMeasurement
{
    public string Name { get; set; }
    public List<PerfMeasurement> Children;
    public long Ticks { get; set; }

    public int AllChildren
    {
        get
        {
            if (Children == null || Children.Count == 0)
                return 0;
            else
            {
                int sum =0;
                foreach (PerfMeasurement m in Children)
                {
                    sum += 1 + m.AllChildren;
                }
                return sum;
            }
        }
    }
}

There are two interesting features here. First is Children field which holds nested measurements. And the other is AllChildren property that recursively counts all children.

The main measurement class

public static class Metrics
{
    private static readonly IHighResolution highresolution;
    private static readonly long twoAvg;
    
    public static List<PerfMeasurement> RootData { get; private set; }
    private static Stack<PerfMeasurement> stack;
    //         private static int counter;
    
    static Metrics()
    {
        RootData = new List<PerfMeasurement>(100000);
        stack = new Stack<PerfMeasurement>();
        highresolution = Mvx.Resolve<IHighResolution>();
        twoAvg = highresolution.Avg * 2;
    }
    
    public static PerfMeasurement Push(string name)
    {
        PerfMeasurement head;
        if (stack.Count == 0)
        {
            head = new PerfMeasurement { Name = name };
            RootData.Add(head);
        }
        else
        {
            PerfMeasurement previous = stack.Peek();
            head = new PerfMeasurement { Name = name };
            if (previous.Children == null)
                previous.Children = new List<PerfMeasurement>();
            previous.Children.Add(head);
        }
        stack.Push(head);
        return head;
    }
    
    public static void Pull()
    {
        stack.Pop();
        if (stack.Count == 0)
        {
            PerfMeasurement m = RootData[RootData.Count - 1];
            OffsetParents(m);
            Print(m);
        }
    }
    
    private static void OffsetParents(PerfMeasurement m)
    {
        m.Ticks -= m.AllChildren * twoAvg;
        if (m.Children != null)
        {
            foreach (PerfMeasurement child in m.Children)
                OffsetParents(child);
        }
    }
    
    public static void Print(PerfMeasurement metric)
    {
        StringBuilder sb = new StringBuilder();
        Print(metric, sb, 0);
        MvxTrace.TaggedTrace("metrics", sb.ToString());
    }
    
    public static void Print(PerfMeasurement metric, StringBuilder sb, int depth)
    {
        string prepend = new string(' ', depth * 4);
        sb.AppendLine(string.Format("{0}{1} took {2:#,##0}", prepend, metric.Name, metric.Ticks));
        if (metric.Children != null && metric.Children.Count > 0)
        {
            foreach (PerfMeasurement child in metric.Children)
            Print(child, sb, depth + 1);
        }
    }
}

This class acts like a Stack for measurement items defined in earlier one. When item at the root level is pulled it outputs the results of the whole hierarchy linked to it into the (MvvmCross) logging mechanism (Print methods). But before doing that it recursively subtracts the nanoTime() invocation of all children (OffsetParents - for each children it assumes nanoTime() took two average invocations – hence the static field twoAvg).

That’s all we need. However there is one step that will make measurement a bit easier and more clean.

 

Making it easier to use Metrics with a helper class

public class MeasurePerf : IDisposable
{
    private static readonly IHighResolution highresolution;

    private long start;
    private PerfMeasurement m;

    static MeasurePerf()
    {
        highresolution = Mvx.Resolve<IHighResolution>();
    }

    public MeasurePerf(string name)
    {
        m = Metrics.Push(name);
        this.start = highresolution.Ticks;
        
    }

    public void Dispose()
    {
        m.Ticks += highresolution.Ticks - start - highresolution.Avg;
        Metrics.Pull();
    }
}

This class is intended as a wrapper around measured code using using keyword. Measurement looks like:

using (new MeasurePerf("Your comment here"))
{
    // your code here
    // nesting measuring is perfectly fine
}

Here is a sample output I’ve been looking at:

profiler_results

I highlighted the root item. All items are showing their total time (children included). Note the negative numbers. That happens because this kind of measurement isn’t accurate at all (remember, I am subtracting twoAvgs). However it gives you at least some insight of what code is slow and which child is guilty.

So, that’s it. Until Xamarin gives us profilers there is no better way AFAIK. Unfortunately. There is one thing you can do, though. You can tell Xamarin that we need profilers. Perhaps through my uservoice suggestion.

Strong typing views in ASP.NET MVC

Did you ever wonder why do you have to write code like:

public ActionResult SomeAction() {   ... return View("SomeView", model); }


instead of this beauty:

public ActionResult SomeAction()
{    
...
  return Views.Home.SomeAction(model);
}

Note the advantages:

  1. Path to view is strong typed. No more “SomeView”.
  2. model argument is strong typed as well. No more passing a wrong typed only to discover the error at runtime.
  3. You can’t pass a non-performing argument anymore. This happens when you pass a view name and that view isn’t stored where MVC expects it to be: in a default folder (with the same name as controller under Views folder). Instead MVC will search for the view using various file-system locations and thus loosing valuable time. Lesson learned from Whiletrue's ASP.NET MVC presentation at SLODUG.

Sounds good? If yes, read further.

Instructions

There is a single requirment: you’ll need (my preferred) template based code generator CodeSmith.

1. Create a root folder named CodeSmith in your ASP.NET MVC project.

2. Unzip the attached CodeSmith template named StrongTypedViews.cst and put it into the folder mentioned above. Include it into the project. The project should look like this:

stv1

3. Right click on CodeSmith folder and add a CodeSmith Project item next to the StrongTypedViews.cst item. Name it CodeSmith.csp.

4. Right click on CodeSmith.csp and select Manage Outputs entry. You should see a modal window like this:

stv2

5. Click Add Output button (first enabled one from the left).

6. Type in StrongTypedViews.cst in the text field of the Template group (or click […] button next to it and select StrongTypedViews.cst). Name field should be auto populated with the same name.

7. In the File group select the radio button near text box and type in ..\Controllers\ControllerBase.cs (or do the same using […] button).

8. Finally, type in the root namespace of your project, MvcApplication4 in my case, into the RootNamespace property on the right side. The complete entry should look like this:

stv3

 

 

9. Click OK and another OK. At this point Visual Studio might warn you that a file has been modified outside the source editor. That’s fine as the previous steps did actually modify CodeSmith.csp file. Click Yes to reload it.

10. Generate the strong typed views by right clicking CodeSmith.csp and selecting Generate Outputs. You should see a new file names ControllerBase.cs under Controllers folder, like this:

stv4

 

 

11. One final step remains. Derive your controllers from auto generated ControllBase class and that’s it. You are now free to use strong typed views. You’ll find them by calling Views property and the with the same structure as it appears in the solution explorer.

stv5

i.e. if you want to return Index view you would use syntax like:

return Views.Home.Index();

or you can pass it a model, through an overload of the Index() method. Note that the model argument is strong typed (or object if the type isn’t specified in the aspx file). The syntax is same for both “full” and partial views (remember, they are strong typed and they know what to return) – no need to call either View or PartialView method.

12. If your views do change and they will you’ll have to recreate ControllerBase.cs class. This is really simple. Save all the view files and re-run Generate Outputs on the CodeSmith.csp project (as in step 10.). You can also set code generation on each build if you prefer.

That’s it.

Implementation details

Read this chapter if you are interested in inner working of this approach.

There are three distinct parts of the generated code.

ControllerBase class

You are required to derive your controllers from ControllerBase class for a simple reason – it provides Views property which is a gateway to all the views. The other (internal) feature of ControllerBase is to provide access to both View() and PartialView() methods to generated code (they are protected internal).

The Views property returns a new instance of ViewFolder auto generated class. Code is pretty much self-explanatory and looks like this:

public partial class ControllerBase: Controller
{
... 
  public new ViewResult View(string path, object model)
{
    return base.View(path, model);
}
  public new PartialViewResult PartialView(string path, object model)
{
    return base.PartialView(path, model);
}
  protected ViewsFolder Views
{ get { return new ViewsFolder(this); } }
...
}

 

ViewFolderBase class

This class is implemented within ControllerBase class and servers as a base class to the classes generated for each folder

public class ViewFolderBase
{
  protected readonly ControllerBase controllerBase;
  public ViewFolderBase(ControllerBase controllerBase)
{ this.controllerBase = controllerBase; }
}

Its main purpose is to “transport” the ControllerBase reference from one class to the another. This transportation is required because the reference to ControllerBase is required by the final class in the chain to call either View or PartialView method.

Classes generated for each folder under Views folder

Each such class (ViewFolderBase derived) is named by the folder it represents and a “Folder” suffix. It represents a single folder in the Views folder structure in the solution. These classes are declared within ControllerBase to reduce their scope. They have a two set of properties:

  • Views properties where there are two overloaded methods for each view in that folder. One overload is without arguments and the other contains a single strong typed model argument (which might be an object when the model is not typed in the view).

i.e. Error view from Shared folder. Note the strong typed model argument in the second overload. Note also the full path to the aspx file.

	public ViewResult Error()
	{ return controllerBase.View("~/Views/Shared/Error.aspx"); 
	
	public ViewResult Error(System.Web.Mvc.HandleErrorInfo model)
	{ return controllerBase.View("~/Views/Shared/Error.aspx", model); }	
	

  • Subfolder properties which represents subfolders of that particular folder. The purpose is to allow chaining.

i.e. ViewFolder’s (representing Views folder) subfolders section:

	public AccountFolder Account
	{ get { return new AccountFolder(controllerBase); } }
	
	public HomeFolder Home
	{ get { return new HomeFolder(controllerBase); } }
	
	public SharedFolder Shared
	{ get { return new SharedFolder(controllerBase); } }	
	

 

 

Template properties

Besides the RootNamespace property mentioned in the step 8 of the instructions there are other properties.

stv6

  • ViewsFolder: relative path to the Views folder in the solution
  • AdditionalNamespace: namespaces you want to place (using statement) in the generated ControllerBase.cs class. This is useful because model type is just copied from the declaration in the view files. So if you don’t use fully qualified types then you should put those namespaces in this property.
  • IncludeControllersNamespace: includes the namespace (a shortcut to the putting this namespace into AdditionalNamespaces)
  • IncludeModelsNamespace: includes the namespace (a shortcut to the putting this namespace into AdditionalNamespaces)
  • RootNamespace: the root namespace of your project. It will be used to compose a namespace where ControllerBase will reside (.Controllers suffix is automatically added).

Performance considerations

The generated code should perform very well. On the positive side it forces full path to the view files so the file is found at runtime in first attempt. On the negative side there is some overhead because the chaining creates few classes and passes a reference to ControllerBase instance to them. It shouldn’t be a huge overhead, or better, I didn’t even notice it in my simple performance tests (10.000 times calling each page using single core).

  • using View(“About”): ~658 requests/s
  • using View(“AboutX”): ~580requests/s   (it searches the Home folder first and Shared folder next where it finds AboutX.aspx)
  • using Views.Home.About(): ~658 requests/s

Tests were simple but I am pretty much confident in the results. Note the performance drop in the second case when MVC does file searching. All in all the overhead is pretty non existing. And it is non existing if you take into considerations all the benefits.

But if you want full performance without overhead there is a way. Instead of chaining used one might opt for method name composition which would result in:

return Views_Home_About();

 

for the About view. This way there wouldn’t be any overhead at all. I prefer my approach but that’s subjective.

Final words

Being a “strong typed” developer I find this approach a good one from every perspective. It should reduce errors if not improve performances as well. And all this for free – no manual typing required.

In the open source spirit of the ASP.NET MVC I am giving the template for free. Use it as you wish. Let me know if you have made improvements though – I’d be interested in seeing them and perhaps incorporating them.

Comming next: strong typed routes.

StrongTypedViews.zip (2.02 kb)