On the Performance of WinRT/Xaml Template Expansion

By jay at February 02, 2013 15:11 Tags: , , , , , ,

TL;DR: Expanding data-bound item templates in Xaml/WinRT in Windows 8 is about a hundred times slower than with Xaml/WPF. This article details how this was measured and a possible explanation.

 

In Windows 8, Microsoft has a introduced a whole new Xaml stack, codenamed Jupiter, completely re-written to be native only.

This allows the creation of Xaml controls using C++ as well as C#.

I will not discuss the philosophical choice of ditching managed WPF in favor of a native rewrite, but make a simple comparison of the performance between the two.

 

Template Expansion Performance

I worked on a project that had performance issues for a UI-Virtualized control, where the initial binding of data as well as the realization of item templates, was having a significant impact on the fluidity of the scrolling of a GridView control.

To isolate this, I created a simple UI:  

<GridView x:Name="testGrid">
    <GridView.ItemsPanel>
        <ItemsPanelTemplate>
            <VariableSizedWrapGrid />
        </ItemsPanelTemplate>
    </GridView.ItemsPanel>
    <GridView.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding}" Foreground="Red" />
        </DataTemplate>
    </GridView.ItemTemplate>
</GridView>

Initialized with the following code in a button click :

testGrid.ItemsSource = Enumerable.Range(1, 100);

On a Surface RT tablet, the time during which the UI was not responding was about 2.1 seconds.

Looking a the profiler revealed that a lot of time was spent in this function :

?MeasureOverride@FrameworkElementGenerated@DirectUI@@UAAJUSize@Foundation@Windows@@PAU345@@Z

Measuring is expected to take some time to execute, but it was very odd that it was that much.

 

Measuring between WPF and WinRT

As an experiment, I tried to create approximately same layout in WPF, and test the rendering performance on my PC.

To measure more precisely, I created an override of both the GridView and the ListBox controls so that the call to Measure could be profiled, that way :

protected override Size MeasureOverride(Size availableSize)
{
   var w = Stopwatch.StartNew();
   try 
   {             
      return base.MeasureOverride(availableSize); 
   }
   finally        
   {                 
      MeasureTime = w.Elapsed;    
      Debug.WriteLine("Measure " + w.Elapsed);         
   }       
}

It turns out that the initial measure duration for 500 element is quite different: WPF measures for 15ms, WinRT does in 1500ms ! And it appears visually, because the UI is not responding a long time in WinRT, where it does not in WPF. Subsequent measures are roughly the same for both platforms.

Interestingly, while the VS2012 profiler does not show stack traces below the manaded/native boundary, the concurrency visualizer does. A stacktrace element that comes back very often is the following :

 

windows.ui.xaml.dll!XamlWriter::WriteNode+0x53c
 

Which seems to point in the direction of the lack of template parsing result caching…

 

What then ?

That’s the problem. Not that much, apart from try to not realize too many collection items in WinRT. (and guessing that for the next update of WinRT that may address this)

Another solution can be to Databind an ObservableCollection and add items slowly to yield the template creation on the UI Thread... But this requires some plumbing code to avoid race conditions and sorting issues.

This makes UI virtualization very important with Virtualizing Panels, to reuse as many control instances as possible. This also implies that your visual design should not display too many items at once on the screen, with small logical dimensions.

blog comments powered by Disqus

About me

My name is Jerome Laban, I am a Software Architect, C# MVP and .NET enthustiast from Montréal, QC. You will find my blog on this site, where I'm adding my thoughts on current events, or the things I'm working on, such as the Remote Control for Windows Phone.