Abstract
The gist of this post is that if you use the ProgressBar that comes out of the box with the Windows Phone tools or use the PerformanceProgressBar that comes in the Silverlight Toolkit – you should always set its IsIndeterminate property back to false when you are done displaying it to not use up the CPU and drain the battery.
If you are using an older version of the Silverlight Toolkit – you should update to the latest one, because some of the older ones have a bug that will cause the PerformanceProgressBar to use up the CPU cycles even once you switch IsIndeterminate back to false.
Ideally – you should just use the non-Silverlight-rendered, OS-managed ProgressIndicator like this:
<shell:SystemTray.ProgressIndicator> <shell:ProgressIndicator IsVisible="{Binding IsWaitingForAnOperationToComplete}" IsIndeterminate="True" /> </shell:SystemTray.ProgressIndicator>
ProgressBar and PerformanceProgressBar Performance Profiles
The below graph shows a test application that in a sequence, at roughly 3 second steps
- Adds a ProgressBar control to the logical tree
- Sets its IsIndeterminate property to true
- Sets Visibility to Visibility.Collapsed
- Sets its IsIndeterminate property to false
- Removes the ProgressBar from the logical tree
- Rinse and repeat for PerformanceProgressBar
The above graph shows that both types of progress bar controls keep using up CPU cycles even when hidden and only really stop when you set the IsIndeterminate property to false.
In the next test I reversed the order a bit and I remove the progress bars before trying to hide them or set IsIndeterminate back to false. Here it seems like the PerformanceProgressBar behaves better than the regular ProgressBar that seems to keep animating even when not in the logical tree!
Finally I tried using the native SystemTray.ProgressIndicator property and It seems like it only uses about 50% when both its IsVisible and IsIndeterminate properties are set to true.
Back Story
The last few days I was working on some reported issues with CPU usage of a Windows Phone app when it was seemingly idle. The phone tools include a performance profiler that you start by going to Debug/Start Windows Phone Performance Analysis (Alt+F1) in Visual Studio. I did that and this is roughly what I saw:
It does seem like the CPU is used at 100%. I selected the range from when I knew the application was supposed to not be doing anything and drilled down in the breadcrumb bar:
It seemed like most of the cycles were used by System.Windows.FrameworkElement.MeasureOverride() calls, which indicate layout updates – something that happens a lot when when Silverlight needs to do original layout of the UI or later when you have an animation running that requires layout updates, but I did not see any animation running…
After a couple hours I found that the problem happens when I display a ProgressBar control, but it continues even when I hide it!
I remembered there were problems with that control, but it was a problem with it using a type of animation that requires layout updates and the Silverlight Toolkit has a “better” version called PerformanceProgressBar, that runs the animation without affecting the layout, and switching to that surely worked in that regard. I still saw continued 100% CPU usage though. I think there was some configuration in which I was mostly getting the graph to not have much in the green part, so it was running mostly Application workloads and System threads, but later I could only see graphs similar to the one below:
It seems like the CPU usage is just about the same and only the Compositor Thread is busier because it does more of the work animating the progress bar.
Finally I decided to start switching IsIndeterminate property to false and that fixed it.
References
- Windows Phone app performance and optimization – Jeff Wilcox (MSFT), Build 2011
- http://windowsphonegeek.com/articles/WP7-PerformanceProgressBar-in-depth
- http://cisforcoder.wordpress.com/2010/10/06/tips-for-progressbar-performance-in-wp7/
- http://www.codeproject.com/KB/showcase/WP7-Animations.aspx – mentions using per-frame animations (using CompositionTarget.Rendering event handler instead of Storyboards) might possibly improve the performance even more.
Test Project: http://dl.dropbox.com/u/1192076/ProgressBarsAnalysis.zip
You can read more about the basics of using progress bars here:
http://www.jeffblankenburg.com/2011/11/15/31-days-of-mango-day-15-the-progress-bar/#comment-4224
Had the same problem. App kept using a few % cpu when idle. Setting the progress bar to indeterminate when collapsed fixed the issue. Thanks