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

Комментарии (21)


  1. maydjin
    11.04.2016 01:17
    +2

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


    А сборка то хоть релизная была?


    1. altk
      11.04.2016 10:37

      Конечно, тестировалась релизная сборка. Настройки компиляции релизной сборки не менял, значения были по-умолчанию (ну кроме того, что полностью выключил генерацию отладочной информации.


  1. crea7or
    11.04.2016 04:06

    Проверка границ массивов всё сожрала?


    1. altk
      11.04.2016 11:09

      Нет. В проектах, полагающихся на работу UWP/WinRT API никакие массивы в замере времени исполнения не участвуют.


  1. dordzhiev
    11.04.2016 09:16

    del


  1. g-man
    11.04.2016 10:15
    +1

    Что-то мне подсказывает, что большая часть времени уходит не на работу «в холостую» (и что это может значить в Вашем примере, если код все равно выполняется?), а на работу со строками.
    В C# примере вы используете:
    input = hasher.HashData(input);
    input = Encoding.ASCII.GetBytes(CryptographicBuffer.EncodeToBase64String(input)).AsBuffer();

    Здесь вы сначала хэшируете буфер, потом конвертируете в base64 string, затем в массив, а потом опять в буфер.


    1. altk
      11.04.2016 11:01

      Если вы посмотрите проекты CPPWRL или CPPCX, то сможете заметить, что там работает аналогичный код:

      input = hasher->HashData(input);
      String^ base64String;
      base64String = CryptographicBuffer::EncodeToBase64String(input);
      input = CryptographicBuffer::ConvertStringToBinary(base64String, BinaryStringEncoding::Utf8);
      

      Для удобства восприятия могу его записать так:
      input = hasher->HashData(input);
      input = CryptographicBuffer::ConvertStringToBinary(CryptographicBuffer::EncodeToBase64String(input), BinaryStringEncoding::Utf8);
      

      Кроме того. Привёл к этому же виду код проекта CSWinRT:
      input = hasher.HashData(input);
      input = CryptographicBuffer.ConvertStringToBinary(CryptographicBuffer.EncodeToBase64String(input), BinaryStringEncoding.Utf8);
      

      Результаты стали даже хуже:
      • C# Native — ~195000 миллисекунд
      • C# — ~80000 миллисекунд


      1. g-man
        11.04.2016 13:06

        Так я не спорю, что это будет медленнее. Я говорю, что «в холостую» не совсем верное утверждение. Код не работает в холостую, он просто выполняется так, как Вы его написали — где-то быстрее, где-то медленнее.


        1. altk
          11.04.2016 13:19

          Спасибо за замечание. Внёс изменения в текст статьи.


  1. Alexx999
    11.04.2016 10:33
    +1

    Довелось мне очень плотно познакомиться с WinRT еще когда он только-только появился — а именно, поучаствовать в разработке Microsoft Minesweeper и других «стандартных» игр.
    Могу подтвердить что работает оно невероятно медленно.
    Причины — это урезанное (и очень медленное по сравнению с Win32) COM-based API плюс реализация .NET поверх этого API что убивает остатки производительности (да-да, рантайм .NET не имеет никаких «бонусов» в плане поддержки ОС).
    Произошло так потому, что разработкой WinRT руководил дядька который ненавидел и стемился уничтожить .NET и сделал все что было в его силах чтобы .NET в WinRT работал настолько плохо, насколько это вообще возможно.
    В итоге — приложения .NET работают в WinRT контейнерах заметно медленнее чем ожидается.


    1. melt
      11.04.2016 16:52

      А если не секрет, то чего хотел этот дядька? На чем, по его мнению, нужно разрабатывать для WinRT? Или он в целом хотел сделать платформу так себе?


  1. Diaskhan
    11.04.2016 10:34
    -3

    С++ жил, с++ жив, с++ будет жить,

    www.techempower.com/benchmarks/#section=data-r12&hw=peak&test=query
    Здесь показывается Overhead веб фреймворков. Роза пахнет розой.

    C#-Java это все таки абстракции, Иногда стоит пожертвовать скоростью в угоду удобства. Зато Абстракция дает вам дженерики словари, замыкания )))


    1. ForNeVeR
      11.04.2016 11:09
      +3

      Обращу ваше внимание лишь на то, что абстракции, генерики темплейты, словари и замыкания есть также и в стандартном C++.


      1. Diaskhan
        11.04.2016 11:10

        Managed Code ????


        1. ForNeVeR
          11.04.2016 11:12

          Managed code тоже есть в C++, но называть C++/CLI (или C++/CX) "стандартным" я бы не стал. В замечании выше речь идёт именно о варианте C++, описанном в соответствующих стандартах ISO.


          1. Diaskhan
            11.04.2016 11:14

            Много ли пишут Веб приложения и destop приложения на c++ в СНГ ?? Инструментом для быстрого создания проекта (EE) вряд ли можно назвать с++!


            1. ForNeVeR
              11.04.2016 11:18

              По моему опыту — да, достаточно много серверных компонентов веб-приложений, а также десктоп-приложений в СНГ разрабатываются с помощью C++. Хотя, честно говоря, я так и не понял, к какому заключению это рассуждение должно меня привести.


              1. Diaskhan
                11.04.2016 11:21

                Можете привести пример ?? Там где критична производительность там и оправдано использование с++.


                1. ForNeVeR
                  11.04.2016 11:35

                  К сожалению, меня связывает NDA, так что конкретные примеры привести не вправе. Могу только отметить, что это не публичные проекты, в которых, тем не менее, критично важна производительность в обработке большого количества поступающих запросов. И при этом на C++ пишутся не приложения целиком, а отдельные компоненты или сервера (которые могут общаться как по HTTP, так и по каким-то инхаузным протоколам по мере надобности).


                  Лично я бы тоже не стал называть C++ "инструментом для быстрого создания проекта" — так же, например, как и nodejs. Там, говорят, можно по несколько месяцев фреймворк выбирать ;)


                  Это я к тому, что тут всё-таки зависит от навыков программистов, а не от технологии. Видимо, надобности в массовом штамповании проектов на C++ в индустрии нет, поэтому соответствующего рода инструменты (типа какого-нибудь yeoman) не столь распространены.


                  1. Diaskhan
                    11.04.2016 12:20

                    Это забавно, но я хотел сказать тоже самое!

                    Есть такая штука как https://lwan.ws/
                    А вот инфа насколько она быстра https://www.techempower.com/benchmarks/#section=data-r10&hw=peak&test=json
                    Но это больше для маленького кода там где критична производительность. Писать же на нем Ентерпрайз решения, нееее, да нуу его. Забивать гвозди плоскогубцами, плохая затея.

                    Хотя конечно скорость загрузки потрясает…


  1. bondarenkod
    12.04.2016 14:47
    +1

    Если не ошибаюсь, вот тут про это написано как раз
    Секция Keep your app fast when you use interop in managed code
    Вот тут msdn.microsoft.com/en-us/windows/uwp/debug-test-perf/windows-runtime-components-and-optimizing-interop