Pull to refresh

Многоядерная JIT-компиляция в .NET 4.5

Reading time3 min
Views13K

Исторически разработчики .NET использовали генератор образов в машинном коде Ngen. Это отлично работает, если у вас есть инсталлятор, и вы можете сгенерировать эти образы во время установки приложения. Но в других случаях, например когда у вас нет установщика или вы не имеете доступ к Ngen, ваше приложение будет производить JIT-компиляцию по мере необходимости, что замедлит его загрузку. Разработчики CLR предоставили решение в новой версии .NET – многоядерная JIT-компиляция с возможностью создавать профили оптимизации.

При многоядерной JIT-компиляции код компилируется на двух ядрах параллельно. Чем больше кода вы выполняете во время загрузки, тем более заметным будет ускорение от многоядерного JIT. Вы можете получить уменьшение времени загрузки на 20-50%, что является хорошей новостью для тех, кто разрабатывает большие приложения и не имеют возможности использовать Ngen. Для этого потребуется добавить в ваш код всего пару строчек кода.

Как это работает


В общем случае вам понадобится вызвать всего два метода в своём приложении:
  • Указать место, где будут храниться профили многоядерного JIT,
  • И начать профайлинг, вызвав метод StartProfile.

.NET runtime создаст профиль исходя из последовательностей вызванных методов во время работы вашего приложения. Этот профиль будет сохранён на диск. Проще говоря, при первом запуске произойдёт «запись» профиля (картинки взяты отсюда):


Когда приложение будет запущено в следующий раз, .NET runtime проверит на наличие готового профиля и, найдя его, начнёт JIT-компиляцию в той последовательности, в которой они были сохранены в профиле.


Используем многоядерную JIT-компиляцию


Использовать многоядерную JIT-компиляцию просто. В .NET 4.5 присутствует класс System.Runtime.ProfileOptimization, который мы можем использовать для того, чтобы начать запись профиля во время старта приложения. Этот код выглядит примерно так:

ProfileOptimization.SetProfileRoot(@"C:\MyApp");
ProfileOptimization.StartProfile("LaunchProfile");

SetProfileRoot — включает оптимизацию для текущего AppDomain и устанавливает директорию, куда будет сохраняться профиль оптимизации. Этот метод игнорируется на одноядерных комрьютерах.

StartProfile – начинает профайлинг и just-in-time компиляцию для тех методов, которые были записаны в профиль (если он уже есть).

ASP.NET 4.5 включает многоядерную JIT-компиляцию по умолчанию. Если вы хотите выключить эту оптимизацию, добавьте атрибут к compilation в ваш web.config:

<compilation profileGuidedOptimizations="None" /> 

Если вы не можете перейти на .NET 4.5, и хотите использовать эту функциональность в приложении, скопмилированным для .NET 4.0, существует способ включить оптимизацию на компьютерах, которые имеют установленный .NET 4.5.

Если ваше приложение имеет многоступенчатую логику запуска, вы можете вызывать StartProfile в нескольких местах. Например, если после начального запуска у пользователя есть выбор (например в меню) в какую часть программы перейти дальше, вы можете использовать разные профили для разных частей кода. Таким образом вы оптимизируете JIT-компиляцию в зависимости от действий пользователя.

Эффективность


Для больших приложений уменьшение времени загрузки может составить около 50%. Чтобы продемонстрировать это, команда разработчиков взяла редактор Paint.NET, удалила предварительно сгенерированные Ngen образы, и сравнила время и загрузгу процессора в двух случаях:


Это определённо довольно простой и эффективный способ уменьшить время загрузки .NET приложений, которые не используют Ngen.

Больше информации об улучшениях производительности в .NET 4.5 доступно в статье на MSDN:
msdn.microsoft.com/en-us/magazine/hh882452.aspx
Tags:
Hubs:
Total votes 51: ↑41 and ↓10+31
Comments8

Articles