UWP application settings performance

Universal Windows Platform includes the ApplicationData API, that provides easy way to store and retrieve application and user settings. If you use it to read settings very often however, you might run into performance problems. How to deal with them?

Settings performance

Retrieving stored settings with the ApplicationData is very simple:

Given a key you can retrieve your setting like it was a simple dictionary. This way it might seem as if this is an in-memory dictionary that gets populated on app startup and is magically persisted behind the scenes. Unfortunately it seems this assumption is not true.

Benchmark

I have created a simple benchmark to illustrate the problem (check it out here on my GitHub). The sample retrieves a setting in two ways.

Directly using the ApplicationData API :

And indirectly by caching the value first time it is retrieved:

The benchmarks runs the read for both cases 100 000 times in a row. Invariably, the results look like this:

This is a major difference! Direct access through ApplicationData was almost 1 500 times slower than the cached version!

Apparently the caching of ApplicationData  API is either only partial or it actually goes through the file on disk to read the value each time it is accessed (although I doubt this, because then the API would surely be asynchronous). In either case direct access is definitely not ideal for performance intensive applications.

Update: As Petr Hudeček who first encountered this problem in our software project pointed out, the slowdown is probably caused by the fact that reading the value from ApplicationData many times in a row causes multiple memory allocations in the background and which then leads to many garbage collections that are, as we know, very performance expensive.

Settings service with caching

Because we developers love to keep things encapsulated, we would like to bundle the caching functionality with access to ApplicationData  so that we don’t have to think about it twice when developing our apps.

Because UWP settings support two different locations for the settings, we will first define a helpful enumeration:

You may note that there already is a ApplicationDataLocality enum in the UWP API, but I decided against using that because it contains additional values that we will not support like Temporary  or SharedLocal  store.

Now we can start writing the Settings service itself. First we declare a storage field, that will hold the cached settings, that we have already loaded into memory:

To retrieve a setting, we first check if we actually need to read it from ApplicationData  or we have a cached copy we can use.

There is a little bit more to this code:

  • We give give the method a Func<T>  that will create a default value if the setting is not stored yet in ApplicationData
  • We use the SettingLocality  enum to decide if the setting should be local or roamed
  • The forceResetCache  parameter makes it possible to force read from ApplicationData , which might be useful for example when roaming settings are newly synced

The inner RetrieveSettingFromApplicationData  method simply tries to read the setting and returns the default value if not found. We have also included a check to ensure the stored value is actually of the right type.

Now finally we have to store the setting, and that is extremely easy in comparison:

We just store the value and invalidate the cache so that the next access will in fact read the new value.

Source code

The complete code for the settings service is available on my GitHub.

Summary

We have found out that the ApplicationData  API is very convenient but also quite slow if we need to use it very often. For some applications it might even become a performance bottleneck. Fortunately, it is quite easy to avoid this issue using caching.

One Reply to “UWP application settings performance”

  1. Good info, and I’d like to add some other thoughts.

    Anything to do with th disk is poor in UWP, and it looks like, even using synchronous tasks, they go through the sandbox security layer, which adds a major bottleneck. Every time you access something (like a setting from disk) it checks your access rights.

    I’ve often found reading and writing lots of data in a single transaction gives greater performance that multiple small reads. To that end I often use INI files (my own class) as the single read and caching of all data is quicker than reading 100k settings.

    In your cached version, if you need to read all seething at the start of the app, it still takes 6004 ms as no data is cached.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">

*