App performance considerations for Windows Phone 8
[ This article is for Windows Phone 8 developers. If you’re developing for Windows 10, see the latest documentation. ]
Performance is an important consideration when creating apps for a Windows Phone device. A Windows Phone device has a limited central processing unit (CPU) and graphics processing unit (GPU) compared to a desktop or laptop PC. To optimize performance of apps on Windows Phone, several changes were made to the way that XAML processes graphics and other objects. This topic describes ways that you can improve the performance of your Windows Phone apps and includes multiple code samples.
This topic contains the following sections.
- Tools
- Images
- Media
- Hiding and displaying objects
- User input
- Indicate progress for lengthy operations
- Displaying Lists
- Making large numbers of requests for small amounts of data
- App startup
- Understanding threads
- Identifying performance issues for graphics-intensive apps
- Related Topics
Tools
There are several tools available to help you optimize the performance of your Windows Phone app.
Tool |
Description |
---|---|
Helps you identify issues such as slow startup time.slow response time to input, and high battery drain. |
|
Lets you measure, evaluate, and target performance-related issues in your code. |
|
Use the frame rate counters to monitor the performance of your app. |
|
Enables a diagnostic feature that is used during development for performance-tuning your app by showing the areas that are being redrawn each frame. |
In addition, for Windows Phone 8, there are changes in the way that apps are deployed and run on phones when they are distributed through the Store. For more information, see How to test the retail version of your app for Windows Phone 8.
There is more information about these tools in the Identifying performance issues for graphics-intensive apps section.
Images
There are many considerations for including images in your apps that can lead to better performance. This section covers image-specific considerations.
Choosing between JPG and PNG image formats
One of the easiest things that you can do to improve performance in your app is to use the appropriate image format. There are two supported image formats for Windows Phone: JPG and PNG. In general, the JPG decoder is much faster than the PNG decoder and should be used for images that are fully opaque. Images that use transparency should be stored as PNG because JPG does not support transparency. Be aware that while JPG works well for continuous tone images, including photographs, it may cause ringing and blocking artifacts in images with varying colors and gradients.
Image creation
A Windows Phone OS 7.1 performance optimization worth noting is the option to move image decoding to background threads instead of blocking the UI thread. This can be achieved by setting the CreateOptions attribute to BackgroundCreation. For example:
<Image Height="100" Width="100" Margin="12,0,9,0">
<Image.Source>
<BitmapImage UriSource="{Binding ImgURL}" CreateOptions="BackgroundCreation"/>
</Image.Source>
</Image>
Choosing between images and XAML
In Expression Design, you can create complex visuals. You can export these visuals as XAML or as image files. When the visuals are static, you should consider storing them as an image instead of XAML. In contrast to decoding and rendering an image, XAML can potentially require more processing. Using XAML for a visual requires parsing the XAML, creating the object in the visual tree, and rendering the object. For example, if you were creating a checker game app, you could create a complex design for each checker in the game using Expression Design. However, since a checker is static, it is better for the app’s performance to export the checker as an image rather than XAML.
Limit image size
Due to the limited screen resolution of Windows Phone, another way to optimize performance is to limit the image size to 2000 × 2000 pixels, which is the size limit of images in the Windows Phone environment. Larger images will be sampled at a lower resolution. Also, if you use images that are larger than 2000 × 2000 pixels, they will be significantly slower to appear.
If you must use images larger than 2000 × 2000 you should only display a portion of the file that meets the 2000 limit. You can do this by loading the image into a WriteableBitmap and using the LoadJpeg(WriteableBitmap, Stream) extension method. The following code shows the recommended way to load a large image.
<StackPanel>
<Image Height="3000" Width="3000" Name="image1" Stretch="Fill" />
<Button Content="Load" Height="70" Width="152" Click="btnLoad_Click" />
</StackPanel>
private void btnLoad_Click(object sender, RoutedEventArgs e)
{
StreamResourceInfo sri = null;
Uri uri = new Uri("LoadJpegSample;component/Test3k3k.JPG", UriKind.Relative);
sri = Application.GetResourceStream(uri);
WriteableBitmap wb = new WriteableBitmap((int)this.image1.Width, (int)this.image1.Height);
wb.LoadJpeg(wb, sri.Stream);
this.image1.Source = wb;
}
Media
The MediaElement in Windows Phone relies on native media processing and hardware decoders that are part of the Windows Phone operating system. Because of this there are two differences in how media is processed and played back that developers should be aware of:
Playback rate and resolution are limited on Windows Phone.
In-memory streams are not optimized for playback.
Encode media for optimal playback rate and resolution
You should encode media to meet the optimal playback rate and resolution required by wphone. For a full list of supported media codecs and the optimal playback rates and resolutions, see Supported media codecs for Windows Phone 8.
Set build action to content for media
Media processing on Windows Phone is optimized to use files and network streams, but not in-memory streams. This means that any media files included in the app, such as sound effects, should have their Build Action set to Content and not Resource. When a media file is compiled as content, it is stored as a loose file alongside the app file (.XAP) and is not stored inside it. When a media file is compiled as a resource, you typically access it by retrieving a stream to the file, which can decrease performance. Also, when a media file compiled as content is played back, it is played directly. When a media file is compiled as a resource, the content is copied to a file on Windows Phone before playback, which decreases performance. The following illustration shows how to set the Build Action of a file in Visual Studio.
If you have to play back an in-memory stream, you can provide an implementation of MediaStreamSource. If you cannot provide an implementation of MediaElement, another solution is to save the stream to a file in isolated storage and access it from there.
Hiding and displaying objects
There are two ways that you can hide objects on the screen. You can use the Visibility property or the Opacity property. By understanding the performance implications of each technique, you can optimize the transitions in your app.
Visibility property
When you set the Visibility property of an element to Collapsed, XAML does not hold any visual data for the element in visual memory and does not do any processing related to the element. However, when you bring the element back on the screen, by setting Visibility to Visible, the contents of the visual tree have to be drawn again. The element is redrawn completely.
Opacity property and bitmap caching
You can improve performance in your app by manipulating the Opacity property of elements when you are using bitmap caching. You use bitmap caching by setting the CacheMode property to BitmapCache. Bitmap caching allows visual elements to be stored as bitmaps after the first render pass. After the element is cached, the app bypasses the render phase for the cached visual element and displays the stored bitmap instead. You should avoid manipulating Opacity without caching enabled as this could decrease the performance of your app.
When you set the Opacity for a cached element to 0, a bitmap representation of the element is saved in memory. This element will remain in memory as long as there are no changes to properties that are not supported by the composition thread. When Opacity is set back to a non-zero value, standard fill rates apply.
Choosing between visibility and opacity
Typically, you will improve your performance by using the Opacity property with bitmap caching. However, there are times when using the Visibility property will have better performance, such as when your app contains multiple rich visuals. You should evaluate the performance of each technique on a case-by-case basis. You can do this by writing code that switches between the Visibility and the Opacity properties.
Hiding objects sample
This sample enables you to experiment with setting the Opacity and Visibility properties to determine which performs better in the app.
When you run this sample you will see 1 blue square with an animation applied, 1 red square with an animation applied, and 150 rectangles. You will also see the following buttons:
Opac x% - Sets the Opacity of the rectangles to the specified percentage.
Cache – Toggles whether the rectangles are cached. The default is true.
Collapse/Visible – Toggles the Visibility property of the rectangles. The default is Visible.
To test this sample, try the following:
Toggle the Visibility and change the Opacity of the rectangles. Notice the rectangles appear much more quickly when the Opacity is changed versus Visibility. Also notice that when Opacity is a value other than 0, the animations are slow. This is because the 150 rectangles are contributing to the fill rate.
Manipulate the rectangles with the cache disabled. You will notice the animations of the squares are smooth because the rectangles are not contributing to the fill rate. You should also notice there is no difference in the time it takes to show the rectangles when setting Opacity or toggling Visibility. This is because without caching, the rectangles must be redrawn in all cases.
User input
User input in Windows Phone includes manipulation events, mouse events, and touch events.
Use manipulation events
Manipulation events are the recommended way to handle user input. Unless you have a specific need, you should avoid using mouse events in your Windows Phone apps for performance and hardware compatibility reasons. Instead, you should use manipulation events. You can also use Tap, DoubleTap, and Hold events on any elements that derive from UIElement such as the base controls.
The Touch class provides the FrameReported event that is used to get individual touch contact points. Although this event is supported in Windows Phone, it is not recommended if you are trying to process gestures, such as pinch and stretch. If you do not need individual touch contact points, you should use the manipulation events.
For more information about how to use manipulation events, see How to handle manipulation events for Windows Phone 8.
Indicate progress for lengthy operations
You should use a progress indicator when performing a time-consuming operation to indicate to the user that your app is still working. To indicate progress, you can use one of the following controls.
You can use the ProgressIndicator to display a progress indicator in the system tray. Built-in apps typically use the ProgressIndicator.
You can use the progress bar control in the Visual Studio Toolbox. For more information about how to use this control, see the ProgressBar class.
Use PerformanceProgressBar instead of ProgressBar when developing with Windows Phone SDK 7.1
If you are using Windows Phone SDK 7.1, using the progress bar in the Visual Studio Toolbox to report indeterminate progress can decrease the performance of your app. In Windows Phone SDK 8.0, the ProgressBar class has been updated and using the progress bar found in the Toolbox will not decrease the performance of your app on Windows Phone 8.
To address the performance issue with ProgressBar in Windows Phone SDK 7.1, Microsoft created an unsupported alternative named PerformanceProgressBar. PerformanceProgressBar moves the animation from the UI thread to the compositor thread. For more information, see Adding a custom indeterminate progress bar.
Displaying Lists
In Windows Phone 8, you have the option of using the LongListSelector to display lists of items, and this is the preferred control compared to the ListBox control.
Making large numbers of requests for small amounts of data
To preserve battery life, the operating system will turn off the device’s radio after a preconfigured timeout interval. If an app is going to make a large number of requests for small amounts of data, we recommend that these requests be executed in parallel instead of serially. This helps to ensure that the device’s radio stack will not go to sleep, avoiding the lag incurred when the radio is powered on and off for each request.
App startup
There are many things you can do to improve performance when your app is loading and starting. This section covers these items.
Use a splash screen
Your app design may want to preload certain resources and assure that these are available before the app is ready for interaction, even if that means not displaying the app until the download is complete. The splash screen is an initial content area that can appear to the user while other content is still loading.
Warning
Typically Windows Phone 8 apps start very quickly and a splash screen is not necessary.
Windows Phone SDK 7.1 project templates include a default splash screen image named SplashScreenImage.jpg. It will automatically appear while your app is starting. You can modify the default splash screen image provided in the Windows Phone SDK 7.1 project templates or you can add a splash screen to Windows Phone SDK 8.0 projects Create your own image to show branding and product information, such as disclaimers for your app.
To customize the splash screen, you can substitute your own image for the default image. You can replace the default image with any image you choose, but it must be the correct size, and it must be named SplashScreenImage.jpg. You can show branding and product information, such as disclaimers for your app or other information. For Windows Phone OS 7.1 apps, the splash screen image must be 480 × 800 pixels. For Windows Phone 8 apps, the image should be 768 × 1280 pixels. The image scales to the correct resolution of the phone that is running the app. You also must set the Build Action property of the image to Content.
For more information about adding or modifying the splash screen, see How to create a splash screen for Windows Phone.
Another option is to show a screen capture of the first page of your app, to give the impression that your app is starting quickly. If you want to use a screen capture of your app for the splash screen, consider the following when taking the screen capture:
Hide any data that changes when your app runs.
Ensure the emulator is set to 100 percent scale.
Crop the image to remove the emulator chrome.
Ensure that your image is the correct size and is saved as SplashScreenImage.jpg.
For apps that take a long time to load, we recommend that you create an animated splash screen to indicate progress while your app prepares run.
If you want to show important information in the splash screen without delaying load time, make your initial screen an exact replica of your splash screen. For example, you can override the OnNavigatedTo(NavigationEventArgs) method for your page and create a popup that contains the same splash screen image and show it for the length of time that you want the splash screen to appear.
Minimize the size of app assemblies
Another way that you can improve the startup of your app is to minimize the size of the app assemblies. When you submit your apps to the Windows Phone Store, they are signed for verification purposes and the signature is checked each time the app starts. The amount of time it takes to check the assembly signatures increases as the size of the app assemblies increases. The impact of signature checking should be limited on subsequent loads of an app because it is cached, but the first load of the app will still be impacted. The following are some tips to reduce the size of your assemblies:
When possible, do not include resources, such as images, media, and XML files, in your assembly with the Build Action set to Resource. Instead, set the Build Action for these files to Content.
Set the Source URI path for an image using a leading slash, such as “/folder/myImage.jpg”.
Use JPG images instead of PNG images, unless transparency is required.
If your app is localized, do not include localized resources in the main app assembly. Instead, create satellite assemblies for each language. For more information, see How to build a localized app for Windows Phone 8.
Note
If you are creating a reusable control or component, you should include the resources with the app by setting their Build Action to Resource. In this case, you should use images and resources sparingly.
Break the app into smaller assemblies
To minimize startup time, you can break your app into smaller assemblies that are loaded only if needed. You do this by adding a new Windows Phone Class Library project to your app to hold pages to be loaded on demand. You then add Windows Phone pages as needed to the project and reference the class library project from the main app project. You can use a hyperlink button or add events for the user to navigate between pages. The following code examples show how to navigate to a page named ExternalPage.xaml located in an assembly named PageInExternalAssembly.
private void button1_Click(object sender, RoutedEventArgs e)
{
// Use the name of the separate assembly when generating the Uri for the page
NavigationService.Navigate(new Uri("/PageInExternalAssembly;component/ExternalPage.xaml",
UriKind.Relative));
}
Minimize the code in constructors and loaded events
All constructors and code in the Loaded event handler for the page is run before the first frame of an app is shown. Page and control constructors parse XAML and instantiate objects declared in the XAML, which can be time consuming. Because of this, you should limit other long-running operations in these methods. If you need to load files or do other heavy processing, you should do this in a later event or schedule them on a background thread. One way that you can do this is to override OnNavigatedTo(NavigationEventArgs) and start long-running processes in this method. OnNavigatedTo is called when a page becomes the active page. The following example shows how you might do this.
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
// Do lengthy page initialization in a new
// thread so the UI can continue to update.
System.Threading.Thread startupThread =
new System.Threading.Thread(new System.Threading.ThreadStart(initializePage));
startupThread.Start();
}
void initializePage()
{
// Do lengthy page initialization here...
}
Monitor the use of isolated storage
The ApplicationSettings object is a singleton that is allocated and deserialized from storage on the first use of the object, typically when the app is starting. You can create a helper property in your app to access ApplicationSettings and measure the time spent deserializing the app’s settings by placing a timer in the helper property. If the data deserialization operation takes more than 100 milliseconds to complete, then you should consider moving this to a call on a background thread.
If you are populating a page with data from isolated storage, you should allocate ObservableCollection<(Of <(T>)>) objects to hold the data and bind the collections immediately to elements in the UI. Then you should populate the ObservableCollection objects with data from isolated storage. If necessary, you can break the data population over several calls by using the BeginInvoke(Action) method.
Avoid blocking the UI thread
There are many ways that you can block the UI thread and therefore delay startup of your app. The following services and APIs can block the UI thread: location services, push notifications, network information, and radio.
Location services
After Windows Phone starts, it can take several seconds for a PositionChanged event to occur on a GeoCoordinateWatcher. Depending on the setting for DesiredAccuracy, 3 to 13 seconds can elapse before the PositionChanged event occurs for the first time. This is due to the time it takes for the location service to start the service, locate satellites, and perform other operations. If Windows Phone is already running, this operation does not take as long and typically the PositionChanged event will occur before 500 milliseconds. If you have calls that rely on the occurrence of location event, you can block the UI thread and slow the startup of your app. For more information about how to use location services, see Location for Windows Phone 8.
Push notifications
The Microsoft Push Notification Service enables you to receive updates in your app from a Web service. The push notification API is asynchronous because some calls to the Push Notification Service may take a long time to return. You should always avoid a situation where the UI thread is waiting for a call to the Push Notification Service to return. For example, you can create and open a channel to the Push Notification Service on the UI thread, but you would not want to create a situation where the UI thread is waiting for this event to occur. For more information, see Push notifications for Windows Phone 8.
Network information
When Windows Phone starts, it can take up to 20 seconds for the first call to the GetIsNetworkAvailable()()() to return. This is because Windows Phone initially enumerates all the available network connections.
Radio
When Windows Phone starts, it can take up to 3 seconds for calls to the FMRadio class to return. After the radio is initialized, the time it takes for these calls to return should be reduced to 100 milliseconds. You should not set up or tune the radio on the UI thread. Instead, you should use a background thread to do this. For more information, see the section Background threads and asynchronous programming later in this topic.
Understanding threads
The graphics threading architecture for Windows Phone is optimized for devices. Windows Phone supports a composition thread in addition to the UI thread. To understand how to optimize performance for Windows Phone, it is important to understand the two main threads in Windows Phone and how to use background threads.
UI thread
The UI thread is the main thread in Windows Phone. The following is a list of tasks handled by the UI thread.
Parse and create objects from XAML.
Draw all visuals the first time they are drawn.
Process per-frame callbacks and execute other user code.
Maintaining a lightweight UI thread is the key to writing a responsive app.
Composition thread
The composition thread handles some work that the UI thread would normally handle, and therefore improves performance of Windows Phone apps. The composition thread combines graphics textures and passes them to the GPU for drawing.Also, on Windows Phone storyboard-driven animations that run on the composition thread are automatically cached and handled by the GPU on the device in a process called auto-caching.
The composition thread handles simple animations associated with the RenderTransform and Projection properties. The following list shows the animations that the composition thread typically handles.
Note
To use the composition thread, scale transforms must be less than 50 percent of the original size.
In addition, the Opacity and Clip property settings are handled by the composition thread. However, if an Opacity mask or non-rectangular clip is used, these operations will be passed to the UI thread.
Animations and threads
As mentioned previously, storyboard-driven animations are handled by the composition thread. This is ideal because the composition thread passes these to the GPU for processing. In addition, the composition thread can run more frequently than the UI thread if the CPU is overloaded. There are times, however, when storyboard animations do not satisfy the requirements of your app. In this case, you may choose to drive animations in code. These animations are handled on a per-frame basis. In many cases, this is fine, but you should be aware of the implications of running animations on a per-frame callback.
Per-frame callbacks are handled strictly on the UI thread. Animations will update only as fast as the UI thread can process them, and depending on what else is happening in your app, the animations may appear less smooth than if they were running on the composition thread. Also, when you update animations in code, the elements are not automatically cached as they would be if they were updated in a storyboard. If you manually place a bitmap cache on these elements, the transformation and blending is passed to the GPU, but the animation is still being updated on a per-frame callback and processed by the UI thread. In these cases, the animation will update only as fast as the frame rate of the UI thread.
Background threads and asynchronous programming
To avoid complex processes that block the UI thread, you can offload processing to a secondary thread, called a background thread, and do this processing asynchronously. For example, the Web service APIs are all designed to be used asynchronously so they do not block the UI thread. If you use a background thread, then you will have to provide a mechanism for moving data from the background thread back to the UI thread. You can either do this with shared variables and an event to move data back and forth, or by using the BeginInvoke(Action) method to send notifications to the UI thread. Alternatively, you can use the BackgroundWorker class and its event-based mechanisms for asynchronous processing. For more information, see How to use a background worker for Windows Phone 8.
Identifying performance issues for graphics-intensive apps
There are several ways that you can monitor the performance of your app and identify performance issues. One way is by monitoring the memory usage of your app. You can also enable colorization of redraw regions and cache visualizations so that you can visually monitor how these are being used in your app. You can also turn on the frame rate counters made available in Windows Phone Emulator. The frame rate counters enable you to monitor many different performance aspects of your app. The following sections describe how to use these features.
Monitor memory usage
You should monitor the memory usage of your app. You can do this by calling several properties of the DeviceStatus API. For more information, see Device status for Windows Phone 8. You can also use the Windows Phone Store Test Kit to evaluate overall memory usage of your app. For more information, see Windows Phone Store Test Kit for Windows Phone 8
Enable redraw regions
You can visually see what regions of your app are being drawn by enabling redraw regions in Windows Phone Emulator. In your page’s construction, set the EnableRedrawRegions property to true. You can access this property through the current app settings, as shown in the following code.
Application.Current.Host.Settings.EnableRedrawRegions = true;
Now, when you run your app and a region is completely drawn, it is shaded with a color. The colored regions indicate that the CPU and not the GPU is used to perform the drawing. When the CPU is used to draw, it is called software drawing. Software drawing is normal, because everything must be drawn by software the first time it is displayed, but you should look for excessive software drawing. If your app contains flashing colors that change every frame, then you should consider using bitmap caching with those elements.
Enable cache visualizations
You can visually see what graphics textures are being used and passed to the composition thread, which in turns passes them to the GPU, by enabling cache visualizations. To do this, in your page’s constructor, set the EnableCacheVisualization property to true. You can access this property through the current apps settings, as shown in the following code.
Application.Current.Host.Settings.EnableCacheVisualization = true;
When you enable cache visualizations, each texture in the app has a blue tint and transparency applied. This enables you to see the various textures in your app and where they overlap. The darkest shades of blue indicate areas where multiple textures are overlaid on top of each other. You can see hidden objects in your app that might be contributing to a high fill rate. The Windows Phone cache visualizations are slightly different than cache visualizations on other platforms. On other platforms, a tinted area would represent a texture not explicitly cached by the developer. However, on Windows Phone, each tinted area represents a texture that is passed to the GPU for composition. This is important to monitor because as an app becomes more visually complex, it can exceed the capabilities of the GPU.
When you enable cache visualizations, the GPU has to do extra work and can negatively affect the frame rate, so you should not rely on the frame rate counters when using this flag.
Enable frame rate counters
Windows Phone Emulator offers frame rate counters to monitor the performance of your app while you are developing it. The frame rate counters are enabled by default in the App constructor when a debugger is attached, as shown in the following code:
// Show graphics profiling information while debugging.
if (System.Diagnostics.Debugger.IsAttached)
{
// Display the current frame rate counters.
Application.Current.Host.Settings.EnableFrameRateCounter = true;
Note
You may need to set the SystemTray.IsVisible property to false to see the frame rate counters.
The following illustration shows the frame rate counters.
The following table describes each frame rate counter.
Counter |
Description |
---|---|
Composition Thread Frame Rate |
This value refers to the rate at which the screen is updated. It also represents how often supported animations driven by a storyboard are updated. This value should be as close to 60 as possible. App performance begins to degrade when this value is below 30. The text in this counter is red when displaying a value below 30. |
UI Thread Frame Rate |
This value refers to the rate at which the UI thread is running. The UI thread drives input, per-frame callbacks, and any other drawing not handled by the composition thread. The larger this value, the more responsive your app should be. Typically this value should be above 20 to provide an acceptable response time to user input. The text in this counter is red when displaying a value below 15. |
Texture Memory Usage |
This value represents the video memory and system memory copies of textures being used in the app. This is not a general memory counter for the app, but represents only memory that surfaces use. |
Surface Counter |
This value provides a raw count of the explicit surfaces being passed to the GPU for processing. The biggest contributor to this number is automatic or developer-cached elements. |
Intermediate Surface Counter |
This value represents the implicit surfaces generated as a result of cached surfaces. These surfaces are created in-between UI elements so that the app can accurately maintain the Z-order of elements in the UI. |
Fill Rate Counter |
This value represents the number of pixels being painted per frame in terms of screens. A value of 1 represents 480 x 800 pixels. The recommended value is about 2.5. The text in this counter turns red when displaying a value above 3. |
Monitor fill rate
Fill rate is the number of pixels in graphics textures passed to the GPU for composition for each frame. Fill rate is essentially a measurement of how much work the GPU is doing. Because of this, you should be aware of your app’s fill rate as it is easy to exceed the GPU’s capabilities, leading to a drop in frame rate. The frame rate will begin to drop when the fill rate for an app exceeds 2 screens (800x480) of pixels. Typically the drop in frame rate is not noticeable to the user until the fill rate reaches approximately 3.5 screens worth of pixels. You can determine the fill rate of your app by looking at the last number in the frame rate counter. Also, it is important to remember that the frame rate on the UI thread will never exceed the frame rate on the composition thread, so if your fill rate is too high, it will affect the overall performance of your app.
Contributions to fill rate
Every graphics object that requires a texture contributes to the fill rate of the app. The more pixels in the texture, the higher the fill rate. Typically, there are two main contributors to fill rate. The first contributor is the base surface, which is the rectangle that surrounds everything that is not cached. The second contributor is everything that is cached, which includes textures automatically cached on the composition thread and elements cached by the developer by setting a BitmapCache on an element. In addition to the textures cached on the composition thread, the following are also automatically cached.
The target of a plane projection, whether it is animated or static.
MediaElement objects.
ListBoxItem objects.
Children of a ScrollViewer element.
Recommended frame and fill rates
The following table lists the recommended and upper thresholds for counters that you should look for when performance-tuning your apps. It is important to test these counters on an actual Windows Phone device because emulator performance will vary. If there are no animations being processed on the thread, be aware that the counters may stop updating. If you want to see counter values at all times, you can add a very simple, repeating animation to your app during development and testing. You can remove the animation prior to releasing your app.
Counter |
Red Value Threshold* |
Recommended Value |
Upper Threshold |
---|---|---|---|
Composition Thread Frame Rate |
30 Frames/Second |
45 Frames/Second |
60 Frames/Second |
UI Thread Frame Rate |
15 Frames/Second |
30 Frames/Second |
60 Frames/Second |
Screen Fill Rate |
>3 |
<= 2.5 |
3.0 |
*When a counter reaches a certain threshold, it turns red. A red value indicates that there is a potential performance issue.
Fill rate test sample
This sample enables you to add and remove animated rectangles to see the impact on the fill rate. Each rectangle is 1/8 the size of the screen and because of the animation applied, represents one texture.
When you run this sample, you will see three buttons:
Add - Adds a rectangle.
Dlt - Deletes a rectangle.
Hide - Hides the Hide and Add button, changing the Dlt button to Show.
You will also see two numbers in the upper right corner. The first number represents a screen’s worth of pixels in a single rectangle, and the second number represents the total screen’s worth of pixels (fill rate).
To test this sample, try the following:
Add rectangles until the fill rate exceeds 2, and observe that the frame rate drops.
Add rectangles until the frame rate is between 45 and 60. Tap the Hide button and you should see the frame rate increase and the fill rate decrease. This is because the surface that holds the buttons has shrunk. With the two buttons on the bottom gone, the surface only stretches down about 10 percent of the screen, as opposed to 90 percent when the buttons are visible. Tap the Show button to bring your frame rate back down as the surface grows again.
Perspective fill rate sample
The sample enables you to see the effect of plane projections, or perspective transforms, on app performance. Designer-generated XAML often contains many perspective transforms that create nice visual effects, but affect app performance. This sample illustrates the caching behavior of perspectives and animations. Perspective transforms without animations are automatically cached, so adding an animation does not impact performance further. However, adding animations to rectangles with no perspective transforms does have an impact.
When you run this sample, you will see four buttons:
Add - Adds a random rectangle.
Dlt - Deletes the most recent rectangle.
Persp – Toggles whether the rectangles have perspective transforms applied to them.
Animate – Toggles whether the rectangles are animated.
To test this sample, try the following:
Add several rectangles until the animation on the middle square begins to stutter, then toggle the perspective button. You should see the stutter disappear because the rectangles are no longer cached. The rectangles share a single surface with the buttons and text on the page. As soon as the perspectives are applied, they are automatically placed on each rectangle, which adds a surface that contributes to fill rate.
Add several rectangles until the animation on the middle square begins to stutter. Tap the Animate button and notice that the stutter does not increase. Because perspectives without animations are already automatically cached, putting an animation on them does not cause any additional textures to be created. Compare this to the behavior of toggling animation on rectangles without perspectives. With no perspectives applied and with no animations except on the square, you can add as many rectangles as you want and the square animation does not suffer. Since none of these rectangles are cached, they are still all sharing the same surface with the text and buttons. However, as soon as you apply an animation to these rectangles, there is an automatic bitmap cache placed on them, and you will immediately pay the fill rate price for each texture area of the rectangle.
Per-frame callback sample
This sample enables you to see the effects of animating with a per-frame callback versus a storyboard-driven animation.
When you run this sample, you will see a small blue square that is animated with a storyboard (and therefore running on the composition thread), and five buttons:
Add - Adds a rectangle that is 1/8 the size of the screen, animated with a per-frame callback.
Dlt - Deletes the most recent rectangle.
Redraw – Toggles the EnableRedrawRegions debug flag.
Cache – Toggles whether the rectangles have a manual bitmap cache applied to them. The default is true.
Hide/Show – Toggles the visibility of the buttons along the bottom of the screen.
To test this sample, try the following:
Add several rectangles until the blue square and rectangles are visibly stuttering. This is because the manual cache is in place. Because of the manual cache, the square is animating on the compositor thread and the rectangles are animating on the UI thread. Both threads are bound by the fill rate of drawing the rectangles for every frame.
Toggle the Cache button, which will turn off manual cache for the rectangles. You should see the square begin to animate very smoothly, but the rectangles will stutter more. This is because without the cache applied, the UI thread is now drawing the rectangles for every frame. Meanwhile, the composition thread is no longer handling the rectangle textures, so the square is animating very smoothly. When the rectangles are not cached, no texture is held in memory. Each time the rectangle position is updated, the pixels are redrawn from scratch. This expensive operation happens through the CPU and on the UI thread. Meanwhile, the lightweight composition thread is able to update its square at 60 frames a second despite the CPU drain from the rectangles.
Continue to experiment with the redraw and cache buttons. Notice that with redraw regions enabled, if the rectangles are cached, the rectangles will not flash. The flashing means that the object is being redrawn from scratch every frame, which you want to avoid. If the rectangles are not cached, you will see flashing and new tints applied to the rectangles every frame. Note that in this case, the square is not flashing because it is being driven by a storyboard animation and is automatically cached.
Use the performance analysis tool
The Windows Phone Performance Analysis tool is a profiling tool that is installed as a part of the Windows Phone SDK. You can use the performance analysis tool to identify, evaluate and improve the execution and memory performance of your graphics-intensive apps.
For more information, see Windows Phone Application Analysis for Windows Phone 8.
See Also
Other Resources
How to disable features in apps for lower-memory phones for Windows Phone 8
App memory limits for Windows Phone 8
Improving memory and power use for XNA games for Windows Phone 8