Небольшое сравнение производительности UWP/WinRT API языковых проекций

WinRT Language projections

На мой взгляд, в разработке UWP/WinRT приложений сложилась необычная ситуация: компания продвигает использование нативного SDK из управляемой среды. Мне стало интересно, насколько эффективен данный подход. И для ответа, я решил написать несколько приложений, решающих одну и туже задачу, полагаясь на средства предоставляемые UWP/WinRT API.
За результатами моего небольшого теста добра пожаловать под кат.

Постановка задачи


Алгоритм работы каждого приложения включал в себя следующие шаги:

  1. Исполняемой средой вызывается функция Main ()(не удивляйтесь, в приложения WinRT/UWP эта функция всегда существует)
  2. Методу CoreApplication.Run (…) передаётся реализация IFrameworkViewSource, которая возвращает в методе CreateView () интерфейс IFrameworkView
  3. Через несколько шагов инициализации вызывается метод IFrameworkView.Run (), который выполняет активацию основного окна приложения, запускает обработку событий диспетчером и создаёт поток/задачу для выполнения вычислений


Чтобы точнее измерить необходимое время на выполнение вычислений, приложения запускались без отладчика. Значения результата и затраченного времени заносились в поля локальных настроек приложения «Result» и «Time» соответственно.
Последовательность замера времени, необходимого на выполнение всех вычислений, сводилась к следующему:

  1. Инициализация переменных
  2. Запуск таймера/инициализация переменной времени начала
  3. Многократное преобразование: входные данные → SHA256 хэш → Base64 строка → входные данные
  4. Остановка таймера/вычисление пройденного времени
  5. Запись значений в локальные настройки

Для чтения сохраненных значений приложения запускались в режиме отладки, а данные выводились в консоль.

Всего было создано пять тестовых проектов приложений, три из которых использовали в своей работе UWP/WinRT API, а два других полагались на собственную реализацию SHA256 и Base64.
Общий список приложений:

  • CPP (C++). Сишные реализации алгоритмов были взяты из github.com/B-Con/crypto-algorithms.
  • CPPCX (C++ CX). Использует API CryptographicBuffer, предоставляемого UWP/WinRT.
  • CPPWRL (C++). Также использует API CryptographicBuffer, но вызовы осуществляются в манере COM.
  • CS (C#). Взята реализации из github.com/yuriks/SHA2-Csharp/blob/master/Sha256.cs.
  • CSWinRT (C#). Используется API CryptographicBuffer.

Проекты, написанные на C#, кроме обычного исполнения, тестировались также в режиме компиляции с использованием .NET Native.

Результаты тестирования


Тестирование проводилось в двух режимах компиляции и исполнения: ARM и x86.
Ниже представлены диаграммы времени исполнения (значения указаны в миллисекундах).

ARM

x86

Столь значительная разница меня немного удивила. Чтобы разобраться я решил провести профилирование приложений, использующих UWP/WinRT API.
Если свести все скриншоты в таблицу то, можно получить следующее:


Легко заметить причину столь большой разницы: в проекте, написанном на чистом C++ с использованием WRL, время работы кода из библиотеки CryptoWinRT.dll, достигает значения 90 процентов, а в проекте C#, скомпилированном с использованием .NET Native, это значение равно всего 15 процентам. Вот и получается, что большую часть времени проекты, написанные на C#, работают в холостую.

Заключение


Конечно, понятно то, что выбран отдалённый от реальности метод использования UWP/WinRT API. Скорее всего в жизни такой код вообще никогда не встретится. Но факт остаётся фактом, при некотором стечении обстоятельств, ваш код может работать очень медленно только из-за накладных расходов, возникших в следствии использования языковой проекции. Может быть наилучшим решением в этом случае будет альтернативная реализация, выполняющая аналогичные задачи, но без использования системного API.

Исходный всех проектов код доступен по ссылке https://github.com/altk/sha256comparison

© Habrahabr.ru