How we improved Wordament

Now that our v1.6 release is out in the Marketplace, I wanted to take a minute to write an engineering blog on what it took to improve our dreaded finger lag problem: we’ve been battling it for quite a while, so I really hope that some of this content is helpful to other Windows Phone 7 developers out there. We LOVE this platform, and we love the phone, and anything we can do to help other developers not stumble on our mistakes is great, in our opinion.

Fundamentally, Wordament was struggling with two different problems: we had some code running on the UI thread that shouldn’t have, and we had a memory leak—a pretty severe one, actually. We were losing memory game-over-game in a really unclear way, but it was slowly, but surely killing our game’s performance in builds prior to 1.6. In fact, you could sometimes feel the lag start as early as game #3. We knew we had a problem, but we just didn’t have to tools to fix the problem.

Tip #1: If you are a developer and you want some insight into what your app is really doing: go and get the Windows Phone 7.1 (Mango) dev tools RIGHT NOW. Even if you aren’t shipping an app for Mango, these tools are going to help you find your problems in your 7.0 app (just make a copy of your project and upgrade that to 7.1 and the profile becomes available to you). The most important of these tools is the terrific new “Windows Phone Performance Analysis” app. We spent a bunch of time trying to figure out how to get all of our code “off the UI thread” and this tool does a great job of showing you where you are holding up the UI, and where your app is running poorly.

Tip #2: For Windows Phone 7.0 (RTM or NoDo): you need to periodically call the Garbage Collector, explicitly. We didn’t know until recently that the 7.0 release didn’t have a “generational garbage collector”, so to stay light-and-lean, you need to call GC.Collect often (we call it on a regular heartbeat now)—and that makes a really big difference to our working set. Even though we never really got too “fat” memory wise (we never get to the dreaded 90MB auto kill limit), it seems that once your app gets into the 35+ MB limit, the app starts to slow down. We understand that Mango comes with a better garbage collector, so perhaps this tip will no longer be necessary in the future.

Tip #3: Track what you create, track what you delete. This was a bit of a tough pill for us to swallow. C# has a garbage collector and that magically cleans up after you, right? Sort of. Aside from Tip 2 (above), you still have to be careful to explicitly clean up things if you want them to release. For Wordament, we now have a pretty elaborate “Heap tracking system” that watches every allocation and deallocation of objects we create (in Debug builds). We dump the total list in our debug spew every 10 – 15 seconds and watch that count like a hawk. For places where we needed to create Collections, like Lists and Dictionaries, we created our own, generic Debug subclass of those to make sure we are getting rid of those too. The most important little gotchas that we found are:

  • Be very careful to unhook every event handler you hook in your Loaded event in your Unloaded event. Only hook Loaded and Unloaded inside your constructor. Every other event handler should be hooked up in Loaded and Unloaded so that page-to-page navigation cleans itself up. We found a bunch of cases where pages wouldn’t dispose if you had event handlers still hooked.
  • Stop DispatcherTimers, unhook their Tick event, and set them to null! Timers keep pages around if they are enabled.
  • If you use HttpWebRequest, be super vigilant in your error handling that you don’t leave a Stream or Response object open. Close all your streams! Network flakiness on cellphones is a thing. The MSDN sample here: http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.begingetresponse(VS.71).aspx is very good, but still has some lingering memory leaks in flakey network scenarios. We scratched our heads a bunch to find them all. Leaking network objects is bad!
  • Be very careful with List databinding. Do not assume that list clean-up is automatic. If you trickle fill lists, be sure to explicitly clear them when you are done, or all of the item they reference can dangle around.
  • Be very careful with Databinding in general. It’s beauty is its simplicity. Debugging it can be hell. We don’t use Databinding anymore.
  • If you have to sit on a single page for a REALLY long time, consider using controls that you can create and destroy.

Tip #4: If fingering performance matters to you—you have to use Touch.FrameReported and avoid mouse events. This adds a lot of complexity, but the perf win is huge. In many cases, you will be doing your own hit testing (using Silverlight’s FindElementsInHostCoordinates method): here’s an example: http://blogs.microsoft.co.il/blogs/alex_golesh/archive/2009/08/11/silverlight-quick-tip-how-to-perform-a-hit-test.aspx

Tip #5: Don’t forward navigate… Pages are never deleted when you forward navigate, and are only sometimes deleted when you press BACK (in practice the phone seems to free pages that are two navigates away). Again, if you want it to appear like you are navigating forward, consider having one page with multiple view states and multiple controls that you create / destroy.

Tip #6: Try to never have more than one DispatcherTimer. There are instances where we need to have two (where the second is temporary), but you should try really hard to only have one.

Tip #7: Inline all of your DataTemplates! Silverlight has a list template memory leak, that causes whole lists to leak over time: http://forums.silverlight.net/t/171739.aspx (this bug repros on Windows Phone 7.0’s RTM and NoDo Silverlight).

We hope these tips help! We know we have been searching for stuff like this ourselves, so hopefully we can save you some time in the future. If you got here because you are a developer, and haven’t played Wordament, you can thank us by downloading our app and rating us. You might also find that you really like our game!

Thanks for listening,

Team Wordament

About these ads

About Wordament

Wordament is a fun and addictive word game from You vs. the Internet, a Microsoft Studio.
This entry was posted in Uncategorized. Bookmark the permalink.

9 Responses to How we improved Wordament

  1. mark says:

    awesome man, thanks for the tips

  2. Alex Frost says:

    Thankfully quite a few of those are resolved in Mango: for #5 for example you can clean backstack, and for #4 there are new events like OnTap and OnHold which work directly with touch input. And #7 was fixed (I think).

  3. Chorn says:

    There’s a bug in the latest version. The app reports version 1.0.0.1010, I downloaded it very recently when I was notified, so believe it is version 1.6. If you find a word right at the very end of the allotted time, it will show in your found words list and the points for it will be included in game total shown on the phone, but in the ranking list at the end of the game, those points are not included. Ie, if I found a 10 point word right at the end of the game, I could see 100 points shown by the phone as my game score, but 90 points shown in the ranking. Either there must be a window between the game ending when the point score is sent off before game finishes counting up the points, or the points scored are submitted before the game really ends.

    • Wordament says:

      Thanks for telling us. It’s the latter. We submit results to our service exactly at time, but that takes priority over the user-interface, because ranking you is more important. Effectively, you just added a word “after time” and it doesn’t count. We can look at what it would take to fix that in a future update.

  4. Pingback: Bunch of great tips for Windows Phone developers from the Wordament – www.nalli.net

  5. Pingback: Fantastic Performance Tips from Wordament » Windows Phone Developer User Group

  6. timdams says:

    Very interesting post! Thx a lot.

  7. Eli Young says:

    Is #3 still a major problem in Mango?

    • Wordament says:

      #3 covers a lot of ground, so I want to be careful how I answer your question. I also want to caveat, that we have optimized Wordament for the currently shipping OS 7.0, which was the focus of this post. Mango addresses a lot of things and is a terrific update–everyone should get it as soon as it’s available. That said, you will still need to clean up after yourself in Mango. This is a C# thing, not a phone thing. The garbage collector is better in Mango, but still can’t clean up dangling references–of which events and databinding can cause references that make large objects persistent and thus non-collectable.

Comments are closed.