C++/WinRT: Optimizing Activation

Previous: Fun with Agility

Activation and agility have a strange relationship. In the last installment, I talked about agility, but agility also has an impact on activation. When I talk about activation I mean those things that the language projection (any language projection) must do in order to interact with runtime classes. This might be calling some constructor like this:

using namespace Windows::UI::Xaml::Media;

FontFamily font(L"Consolas");

Or it might be calling some static method like this:

using namespace Windows::UI::Xaml;

Window window = Window::Current();

In either case, activation is at play. That’s because in both cases, the activation factory for the runtime class must be retrieved. In the first example, the “Windows.UI.Xaml.Media.FontFamily” activation factory is what actually creates the FontFamily object under the hood. In the second example, it is the “Windows.UI.Xaml.Window” activation factory that actually implements the “Current” property.

Optimizing activation is all about making the retrieval of the activation factory as efficient as possible. James and I talked about how this is done in this presentation at CppCon 2016. The gist of it is that if the activation factory is agile then it can simply be cached via a magic static. Of course, if the activation factory is not agile then it would not be safe to do so since that would allow the factory object to be accessed from a different apartment to the one in which it was created.

Activation factories should be agile, but sadly some are not. Caching agile activation factories is safe since the cached pointer may be used by any thread from any apartment. Non-agile activation factories may only be used by threads from the same apartment and the overhead of managing a per-apartment cache is prohibitive. Non-agile activation factories are also the source of a variety of bugs. We are moving to a world where all activation factories will be agile. This is the most reliable and efficient model, but we need this fallback in C++/WinRT to deal with existing non-agile factories.

One of the nice things about C++/WinRT is that it is a header-only library. That means you can step into those constructors and static methods above and see how they map to the underlying WinRT plumbing. In both cases, you’ll see that they eventually call this function:

template <typename Class, typename Interface = Windows::Foundation::IActivationFactory>
Interface get_activation_factory()
{
    static Interface factory = impl::get_agile_activation_factory<Class, Interface>();

    if (!factory)
    {
        return impl::get_activation_factory<Class, Interface>();
    }

    return factory;
}

How this function is implemented is an implementation detail but you can clearly see what’s going on. The internal get_agile_activation_factory function will only return a valid factory object if the factory implements the IAgileObject interface. This check is done on demand and once per process. Due to the proliferation of required interfaces and static members in the Windows Runtime, the ability to optimize activation factory access is vital in building high-performance apps and components. As we illustrated at CppCon, the approach taken by C++/WinRT performs substantially better than C++/CX. I have also successfully campaigned within Microsoft to have all activation factories eventually becoming agile. This will provide significant performance wins for both existing and new apps targeting the Windows platform. The good news is that there’s nothing you need to do to opt in to this performance. C++/WinRT will give you the best possible performance today and your apps will only get faster as more of the Windows Runtime switches to agile activation factories.

Join me next time as we continue to explore C++/WinRT. Give C++/WinRT a try today. Got a question? Post it here and we’ll do our best to help.

Next: Working with Namespaces

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s