{"id":2553,"date":"2012-03-30T16:58:37","date_gmt":"2012-03-30T14:58:37","guid":{"rendered":"http:\/\/www.centigrade.de\/blog\/en\/?p=2553"},"modified":"2020-02-13T16:24:56","modified_gmt":"2020-02-13T15:24:56","slug":"wpf-performance-2","status":"publish","type":"blog","link":"https:\/\/www.centigrade.de\/en\/blog\/wpf-performance-2\/","title":{"rendered":"WPF Performance \u2013 How It Matters on the User Interface"},"content":{"rendered":"<p>No doubt, when creating software, there is always one topic that everybody talks about: performance. In this respect, even though Windows tries to hide a lot of performance optimization work from the developer\u2019s eyes (when developing for .NET with WPF), there are still a dozen of issues to be kept in mind when implementing a piece of software.<br \/>\nTo start things off slowly: How does computer science define performance? Spoken very generally it is formally described as \u201cthe ability of software to complete certain tasks\u201d (see <a href=\"http:\/\/en.wikipedia.org\/wiki\/Computer_performance\">Wikipedia<\/a>). Most commonly, however, it is simply referred to as the speed of software. In this case, people usually do not differentiate between the user interface\u2019s performance and the performance of the application logic itself.<br \/>\nNonetheless, inside a development team there should be a clear understanding of who is responsible for what performance aspects, rather than pushing away all responsibilities to a single developer alone. Even though performance certainly affects the entire application, many advantages can be gained by distributing optimization tasks to different people regarding their expertise and specialization. For this reason I, as a Design Engineer, put significant effort in performance analyses for our customers and while our customers focus on optimization of C#-based Code, such as the user interface logic or other respective layers below, my area of expertise focuses on optimization of XAML Code.<br \/>\n<!--more--><\/p>\n<h2>Identifying performance problems<\/h2>\n<p>In order to optimize user interface performance, naturally those areas that cause trouble need to be detected and localized. Without appropriate data a performance analysis gets problematical or \u2013 to be more explicit \u2013since development and target system rarely match, \u201cplaying around\u201d really gets you nowhere.<br \/>\nTo get useful and valid data for .NET based software systems, there are, however, a couple of useful tools. Probably the most famous one is the WPF Performance Suite, which is included in the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/windowsserver\/bb980924.aspx\">Windows SDK<\/a>.<\/p>\n<p>To create a performance profile of an application, the user has the following tools at hand:<\/p>\n<h3>Perforator<\/h3>\n<p>Perforator especially helps in analyzing the rendering behavior of an application. By exploiting different types of diagrams a developer can perform a thorough analysis of rendering processes. By doing so, performance issues such as peaks in the CPU capacity can be identified quickly. Making further use of the numerous setting options, it is possible to simulate different configurations of an application, such as runtime behavior with or without opacity effects. Thankfully, as WPF relies on a rendering technique called \u201cdirty regions\u201d, only areas that underwent a change are redrawn. The operation \u201cShow dirty-region update overlay\u201d turns on coloring of those areas that are bound to change during runtime. For UI design engineers, this information gives a first outline, which elements of the application might have a negative impact on the overall performance. At that stage, small changes, such as exchanging a layout container may already lead to small boosts in performance.<\/p>\n<p>Shown below is a screenshot of Perforator, which illustrates the difference between an application with many and one with little rendering operations.<\/p>\n<p><a href=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/DirtyRect1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2639\" title=\"Dirty Rectangle Example\" src=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/DirtyRect1.png\" alt=\"\" width=\"605\" height=\"347\" srcset=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/DirtyRect1.png 1008w, https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/DirtyRect1-300x172.png 300w\" sizes=\"auto, (max-width: 605px) 100vw, 605px\" \/><\/a><\/p>\n<p>The screenshot also depicts an extreme configuration, as the operation \u201cDisable dirty region support\u201d is checked (circled in red). As a consequence, the entire screen is completely redrawn every time an action is performed. Whether this scenario actually occurs in the application at hand can be figured out by using the operation described earlier (circled in blue).<br \/>\nThe need for redrawing the entire screen arises when elements are animated by the use of Expression Blend\u2019s FluidLayout behavior, for example. While being able to animate properties that do not per se allow smooth transitions (such as \u201cVisibility\u201d) it literally eats away performance. One drawing process in this demo application took up to 79 rects\/s, which were changed in the process of an expanding navigation bar. If this animation is instead implemented by using the FluidLayout, which in turn installs a custom visual state manager, the entire window will be redrawn, resulting in the need for 231 rects\/ s for the same animation. Keeping the application\u2019s minimal requirements in mind, one can imagine the drastic performance loss, when used in a complex business application. Therefore, especially when it comes to animation, it is important to find a good balance between \u201ca sexy UI\u201d and reasonable performance. Additionally, the use of animation is also restricted by their contribution to the perceived comprehension of a User Interface.<\/p>\n<h3>Visual Profiler<\/h3>\n<p>The second tool in the WPF Performance Suite provides the means to identify single UI Elements which cause significant performance bottlenecks. The Visual Profiler provides a tree view, which allows for easy exploring of the application\u2019s visual tree. Elements, which have a negative impact on the performance, are colored in shades of red according to their consumption of resources. Darker tones of red naturally represent higher consumption of resources.<\/p>\n<p><a href=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/VisualTree2.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2640\" title=\"Visual Tree Example\" src=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/VisualTree2.png\" alt=\"\" width=\"605\" height=\"346\" srcset=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/VisualTree2.png 1008w, https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/VisualTree2-300x171.png 300w\" sizes=\"auto, (max-width: 605px) 100vw, 605px\" \/><\/a><\/p>\n<p>The screenshot shows data from the analysis of a StackPanel, which is used in the ItemsPanelTemplate of a ListBox. Noteworthy is the area on the right, which details CPU workload and visually presents it as a diagram.<\/p>\n<p>Detailed information about the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/aa969767.aspx\">WPF Performance Suite<\/a> is available at Microsoft.<\/p>\n<h3>DotTrace<\/h3>\n<p>Another useful tool to track down performance problems is JetBrains\u2019 DotTrace, which also provides features that survey memory consumption. This is of relevance as high memory consumption mostly hints at instantiation of many heavy-weight objects and as every instantiation of an object takes time, this again results in a loss of performance. Whereas the WPF Performance Suite is top notch when analyzing performance of the view layer, the DotTrace Profiler targets at optimizing C# Code. During its analysis, it also unfolds the entire \u201cCall Stack\u201d of the application along with the quantity and time of each call. Several calls of the same constructor might for example indicate errors in the virtualization of a certain list. In order to use the DotTrace successfully, one should, however, have a basic knowledge about the C# classes of the application.<\/p>\n<p>More information is available at <a href=\"http:\/\/www.jetbrains.com\/profiler\/\">JetBrains<\/a>.<\/p>\n<h2>What rules of thumb should a Design Engineer adhere to in order to enhance performance?<\/h2>\n<p>As we have already mentioned, there are quite a dozen of potential performance problems that may arise in an application. Most problems are, however, no undefeatable hurdle, as I will explain in the following segment. Moreover, Microsoft has been busy enhancing the general performance since the introduction of .NET 4.0, which is especially reflected in the handling of pixel shaders and rendering of complexly styled elements.<\/p>\n<h3>Effects<\/h3>\n<p>First off, with .NET 4.0 it is possible to develop effects that are based on the pixel shader 3.0 model. In contrast to older releases, version 3.0 comes with a drastically improved shader model. In practical terms that means there are even more effects that support hardware acceleration, which, back on topic, offer a better performance when compared to effects rendered solely by the software. To put it simply: while the graphics card handles rendering, the processor can follow its actual purpose of dealing with computational stuff. In spite of that, a UI design engineer should always consider if there is an easier way of realizing a visual effect. Using a resource killer such as the WPF drop shadow effect to draw a subtle 1 pixel shadow below a label can be avoided by creating a second differently colored label with a respective offset. Simplifications such as these, have proven very useful in practice and should therefore be considered when styling an application.<\/p>\n<h3>Caching<\/h3>\n<p>Another way of enhancing performance lies within the magics of the class <em>BitmapCache<\/em>. It provides a caching option for visually complex UI Elements, so that they are stored and rendered as plain bitmaps. This bitmap caching option can be turned on for every UI Element by setting the <em>CacheMode<\/em> Property within XAML Code, as can be seen below.<\/p>\n<p><a href=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/BitmapCacheCodeSnippet1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2641\" title=\"Bitmap Cache Example\" src=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/BitmapCacheCodeSnippet1.png\" alt=\"\" width=\"605\" height=\"77\" srcset=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/BitmapCacheCodeSnippet1.png 1008w, https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/BitmapCacheCodeSnippet1-300x38.png 300w\" sizes=\"auto, (max-width: 605px) 100vw, 605px\" \/><\/a><\/p>\n<p>Especially for animations this leads to a significant reduction of rendering expenses. Still, attention should be paid to the fact, that elements remain interactive and will consequently receive all WPF events, such as mouse clicks or keyboard inputs. In those cases, the cache will be flushed and the element will be redrawn.<br \/>\nScaling of objects without flushing the cache is however possible. By using the <em>RenderAtScale<\/em> Property, bitmaps are rendered at a certain scaling factor. By default however the element is saved in its original size (at 96ppi). It is recommended to keep a close eye on the results to identify potential visual side effects. For example, one should refrain from using Bitmap Caching on elements that contain texts, as it will certainly affect readability. Moreover, the number of UI elements being buffered should not grow too high to avoid problems with the working memory. An essential aspect in using the Bitmap Caching is the element\u2019s layout. Changing the layout of a control results in the bitmap cache being flushed \u2013 an operation that is pretty expensive. As a consequence, an element\u2019s layout should be changed as little as possible during runtime, or even better, not at all, when bitmap caching is active. To summarize it: with bitmap caching enabled, the operation <em>RenderTransform <\/em>can be used without concern, as opposed to <em>LayoutTransform<\/em>.<\/p>\n<p>Microsoft offers another way to temporary buffer elements. The class <em>BitmapCacheBrush <\/em>is able to define a buffered <em>BitmapCache <\/em>element as <em><strong>BitmapCacheBrush<\/strong><\/em>, which for instance can be applied as background to several elements.<\/p>\n<p><a href=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/BitmapCacheBrushCodeSnippet1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2642\" title=\"Bitmap Cache Brush Example\" src=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/BitmapCacheBrushCodeSnippet1.png\" alt=\"\" width=\"605\" height=\"201\" srcset=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/BitmapCacheBrushCodeSnippet1.png 1008w, https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/BitmapCacheBrushCodeSnippet1-300x99.png 300w\" sizes=\"auto, (max-width: 605px) 100vw, 605px\" \/><\/a><\/p>\n<p>Reusing a buffered element and consequently minimizing drawing efforts will also result in a better performance.<br \/>\nConsequent use of the described classes can reduce CPU load up to a factor of three in some cases.<\/p>\n<h3>Lists<\/h3>\n<p>Usually performance bottlenecks occur when the application needs to visualize a lot of data. UI controls that are frequently used to display data on a User Interface in WPF are <em>ListBox<\/em>, <em>ItemsControl <\/em>and <em>DataGrid<\/em>.<br \/>\nTalking about a list\u2019s <strong>scrolling performance<\/strong> is a very important issue. The class <em>VirtualizingPanel<\/em> offers a way to suppress instantiation of elements in a list, until they actually become visible. This results in a major improvement of runtime behavior, especially regarding the loading times of a list. The bottom line is, when overwriting an <em>ItemsPanel <\/em>of a list, it is recommended to keep the <em>VirtualizingStackPanel <\/em>(which is the default item\u2019s host) as long as possible.<br \/>\nIn addition, the <em>VirtualizationMode <\/em>Property of <em>VirtualizingStackPanel <\/em>offers a good improvement regarding scrolling performance. By default WPF discards list elements as soon as they disappear and consequently recreates them if they scroll back into view. This default behavior, however, is not the best solution at all times. In practice, we often came to realize, that the same element containers are repeated inside a list. In that case, it is worth a thought to disable the constant discarding and recreating of list elements. Setting the property <em>VirtualizationMode <\/em>to \u201cRecycling\u201d, results in the reusing of element containers.<\/p>\n<p><a href=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/VirtualizingPanel1.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2643\" title=\"Virtualizing Panel Example\" src=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/VirtualizingPanel1.png\" alt=\"\" width=\"605\" height=\"38\" srcset=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/VirtualizingPanel1.png 1008w, https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/VirtualizingPanel1-300x18.png 300w\" sizes=\"auto, (max-width: 605px) 100vw, 605px\" \/><\/a><\/p>\n<p>The code snippet above may get you an improvement of up to 40% regarding scrolling performance.<br \/>\nDifficulties will most likely arise, if the scrolling of a list needs to be per pixel, rather than per element. An easy solution comes with setting the <em>CanContentScroll <\/em>property to false. Even though this will result in scrolling to feel very smooth, there is also an unwanted side effect: the big disadvantage of the property is that virtualization will be deactivated, even if a <em>VirtualizingPanel <\/em>is used in the <em>ItemsPanel <\/em>of the list. Accordingly, when styling a list to support smooth scrolling, caution is advised.<\/p>\n<h3>Resource Dictionaries<\/h3>\n<p>A very important issue in big software projects is resource management through <strong>ResourceDictonaries<\/strong>. A specialty of WPF, whether we like or not, is the fact that <em>ResourceDictionaries <\/em>are re-instantiated, every time they are included in a View via a <em>MergedDictionary <\/em>statement. Keeping in mind that frameworks such as Prism dynamically compose views by dynamically instantiating other views, showcases that organization of <em>ResourceDictionaries <\/em>has to be well-planned. To better illustrate the complexity of the problem, the View below details how it could all play out in a real project:<\/p>\n<p><a href=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/ResourcesDiagram6.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-full wp-image-2658\" title=\"Resources Diagram\" src=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/ResourcesDiagram6.png\" alt=\"\" width=\"559\" height=\"412\" srcset=\"https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/ResourcesDiagram6.png 931w, https:\/\/www.centigrade.de\/wordpress\/wp-content\/uploads\/ResourcesDiagram6-300x221.png 300w\" sizes=\"auto, (max-width: 559px) 100vw, 559px\" \/><\/a><\/p>\n<p>Frequent duplication of <em>ResourceDictionaries <\/em>in an application will therefore most likely result in enormous memory consumption. As WPF is infamous for this \u201cproblem\u201d, Google spits out quite a dozen of suggestions, which claim to give an easy solution. Not all of these do, however, qualify as being practicable.<br \/>\nAt first sight, a very promising solution seems to be the use of a <em>SharedResourceDictionary<\/em>, which iniates every <em>ResourceDictionary <\/em>only once and then references these shared instances. This comes, however, with a huge drawback: every <em>ResourceDictionary <\/em>is tagged with a reference to its owning view and the memory that it used up by this view cannot be freed by the <em>GarbageCollector<\/em>. This in turn can result in drastic memory leaks, which can\u2019t be resolved easily.<br \/>\nIn general, resources, which are used more than once, should be included globally via App.xaml.<br \/>\nFurthermore, the method of referencing resources in XAML Code has an impact on runtime behavior. WPF offers two different approaches:<\/p>\n<p><strong>1)<\/strong> When using <strong>DynamicResources <\/strong>\u2013 as Expression Blend does automatically \u2013 it comes with the following effects: while resources may be exchanged during runtime, this also implies continuous reloading of resources every time the view is loaded. So with greater flexibility on the one hand, potentially longer loading times come on the other.<\/p>\n<p><strong> 2)<\/strong> <strong>StaticResources<\/strong>, are completely loaded on startup of an application and there are no additional loading times when a view is opened. Of course, StaticResources also come with a drawback in that they result in longer loading times on startup of the application.<\/p>\n<p>Ideally the decision for either resource type should be made ahead of development, depending on preferences regarding startup and runtime loading times.<\/p>\n<h3>Trigger vs. Visual States<\/h3>\n<p>When I was new to developing with WPF, I often wondered why WPF default templates always visualize States such as \u201cPressed\u201d with the help of a triggers rather than <em><strong>VisualStates<\/strong><\/em>, which are available through their respective <em>VisualStateGroups<\/em>. When thinking in terms of performance, however, the reason is quite obvious. Every visual state change starts up a storyboard that in turn contains further timeline objects. Naturally this consumes more time and memory than simply setting a property in a trigger. As a consequence, <em>VisualStates <\/em>should be handled with care if performance is an issue.<br \/>\nFinally, I want to share an easy to use advice to optimize a user interface. When defining a layout, large quantities of elements in the visual tree, may lead to a significant loss in performance. To avoid this, one should tend to create flat container hierarchies. Also the type of the container itself should not be picked at random or out of personal preference. As far as possible, heavy weighted <em>ContentControls <\/em>should be avoided. This simple rule is especially valuable when creating Control Templates, since these templates are often reused. Assigning a template to ten buttons, which in turn contains ten elements, sums up to one hundred elements in total.<\/p>\n<h2>Summary<\/h2>\n<p>To sum things up, performance optimization of a WPF-based .NET application is not something that only a single developer should be responsible for. Improvement of runtime behavior is something to be done across different specializations and competences to achieve an ideal final result. And that is the reason, why performance analyses and optimizations are part of a UI design engineer\u2019s everyday work. At least at Centigrade.<\/p>\n<p><span style=\"font-size: xx-small;\"> Microsoft, Windows, Expression Blend and Expression are trademarks or registered trademarks of Microsoft Corporation in the US and\/or other countries. <\/span><\/p>\n","protected":false},"author":24,"featured_media":0,"template":"","tags":[42,19,33,34,44],"class_list":["post-2553","blog","type-blog","status-publish","hentry","tag-blend","tag-collaboration","tag-user-interface-development","tag-user-interface-tools","tag-wpf"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.centigrade.de\/en\/wp-json\/wp\/v2\/blog\/2553","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.centigrade.de\/en\/wp-json\/wp\/v2\/blog"}],"about":[{"href":"https:\/\/www.centigrade.de\/en\/wp-json\/wp\/v2\/types\/blog"}],"author":[{"embeddable":true,"href":"https:\/\/www.centigrade.de\/en\/wp-json\/wp\/v2\/users\/24"}],"version-history":[{"count":1,"href":"https:\/\/www.centigrade.de\/en\/wp-json\/wp\/v2\/blog\/2553\/revisions"}],"predecessor-version":[{"id":11276,"href":"https:\/\/www.centigrade.de\/en\/wp-json\/wp\/v2\/blog\/2553\/revisions\/11276"}],"wp:attachment":[{"href":"https:\/\/www.centigrade.de\/en\/wp-json\/wp\/v2\/media?parent=2553"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.centigrade.de\/en\/wp-json\/wp\/v2\/tags?post=2553"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}