Платформа .NET

Из переписки с сотрудником «Империи Зла». Имена и фамилии вымышлены, случайные совпадения — случайны. Орфография и стилистика сохранены. Виновные сосланы на урановые рудники :-)

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

(1) Про managed code в Visual Studio 8 (равно как и в предыдущих – то есть начиная с момента, как «устаревшие» части VS начали переписывать на managed code).
В течение года до ship-а VS8 я имел счастье отвечать за VC Regression Prevention System – т.е. автоматическую систему прогона небольшого количества priority 1 performance тестов (на priority 2 никто давно не глядит). Задача была поймать performance regressions (в IDE, не в компиляторе) фактически сразу после вызвавшего её checkin-а, до того, как регрессия ушла в другие branch-и. Ещё лучше было бы ловить регрессии до checkin-ов, но это было невозможно (очень сложная и нестабильная инфраструктура, случайные флюктуации, долгое время прогона тестов и т.д.). Так вот, наиболее частая и легко распознаваемая регрессия – startup код случайно начинал загрузку CLR. В default настройках VS для C++ тщательно отслежено, чтобы CLR нигде не была нужна; пара окон рисуется managed кодом, но сверху добавлен уровень native кода «если окно пустое – отрисовать и managed код не звать». Какие окна показывать по умолчанию тоже выбиралось исходя из того, укладывается ли startup time в performance goals или нет. Несколько очень полезных окон – все до единого managed – по этой причине по умолчанию выключены. Разумеется, первое, что сделает пользователь – это включит показ этих окон, но ведь это же его проблемы, правда?
CLR в VS Professional загружается background thread-ом после запуска, когда мы всё отрисовали и готовы воспринимать user input. Опять-таки, обычно в этот момент пользователь хочет начать работу, и общая тормознутость активно меняющейся с диском системы её/его бесит, но наверное, это небольшая плата за удобство написания частей Visual Studio на C# или managed C++. Да и вообще, время работы некоторых переписанных частей замедлились по сравнению с VS6 (последней Visual Studio, не использовавшей CLR) всего раза в 2-3.
Я помню бурную дискуссию, когда выяснилось, что VS Team System загружает-таки CLR в процессе загрузки, т.к. они настаивали, что надо сразу показывать некоторые advanced features. Для managment-а было откровением, что продаваемый за безумные деньги продукт работает – а главное, выглядит – ощутимо медленнее, чем VS Professional или бесплатный VS Express. Уж не помню, чем всё кончилось, думаю что сделали «adjustment of performance goals».
Опять-таки, выяснилось, что все эти переписанные компоненты не работают, несмотря на (неоднократный) slip с выпуском VS8, вызванный стремлением их довести до ума. Я не знаю про VB и C# программистов, но C/C++ программисты в массе отказываются уходить с VS6 несмотря на устаревший компилятор, прекращённую техподдержку, бесплатный VS Express и т.д. Крупный заказчик переходит с VS8 назад на VS6, ибо наша безумно красивая система (а) не умеет делать некоторые ыещи, которые старая умела, (б) содержит новые ошибки во вновь переписанных частях, и (в) не справляется с их проектом на миллионы строк кода, и не последнюю роль в этом имеет managed код. Тестировали-то на игрушечных проектах...

(2) Теперь про производительность managed кода.
Сразу скажу, что есть огромное количество случаев, когда managed кодом можно пользоваться, и это правильное решение – с одной стороны база данных, с другой пользователь, надо нарисовать форму и пару окошек – а таких приложений, наверное, большинство. Или на сервере, когда безопасность и гибкость важнее производительности. К моему крайнему удивлению, придя неделю назад в новую группу, я вынужден был согласиться, что их написанный на C++ код (специализированное приложение, не client-side) без ущерба для производительности можно было бы писать на C# или managed C++, ибо основная работа всё равно делается low-level С кодом.
К сожалению, я не могу сказать, что нынешняя архитектура CLR хорошо подходит даже этим приложениям. Пишут от безысходности, ибо всё остальное подходит ещё меньше. И в качестве платы за некоторые удобства платят потреблением куда большего количества ресурсов. Вот тут и зарыта собака – когда апологеты managed кода говорят об «acceptable performance loss» они имеют в виду исключительно замедление работы программы из-за худшего качества сгенерированного JIT-ом кода. Причём сравнивают обычно небольшую программу, которая делает что-нибудь с плавающей точкой, например решает систему линейных уравнений. Т.е. имеется пара массивов и небольшой «горячий» цикл, в итоге (a) startup time не важно, (б) data layout и access pattern для managed и native кода примерно одинаковы, (в) размер сгенерированного кода абсолютно не важен; более того, native код скомпилирован для x86 с помощью VC, а мы на вешественных оптимизациях никогда не блистали.
Те 15% performance loss, про которые писал Дмитрий Кочетов – это и фактически и есть потери «JIT/NGEN vs. standalone optimizing compiler». Они в себя не включают ни startup time, ни managed data – все эксперименты тогда проводились с IJW, т.е. данные оставались unmanaged. Более того, эти 15% – это лучший случай, использовались далеко не лучшие флажки native компилятора.
В реальной же жизни и время запуска чрезвычайно важно, и – особенно – важно сколько памяти потребляет приложение. И не надо говорить, что если мы уложились в выделенные нам ресурсы, то неважно, что могли бы использовать меньше. Это может быть так на специализированной железяке, да и то, для лучшей программы часто можно использовать машинку попроще и сэкономить на железе. На обычном PC у пользователя может работать пара десятков приложений – если Вы читаете это письмо не на выделенной mail-машине, то посчитайте открытые окна. Так вот, то, что приложение сожрёт 50Mb памяти вместо 10Mb, замедлит всю систему. В лучшем случае система выбросит из файлового кэша 40Mb недавно использованных данных и DLL. В худшем – начнёт swap-иться на диск. Потом, когда Вы переключитесь в одну из «старых» программ, начнётся обратный процесс – записали то, считали это. А про то, как работает garbage collector, когда куча выгружена на диск, я вообще молчу.
Даже если оставить в стороне сам JIT-ter, метаданные и прочий хлам, то нетривиальные managed данные занимают значительно больше места, чем (оптимизированные) unmanaged данные. Причин несколько – и необходимость поддержки сборщика мусора, и отсутствие union-ов, и отсутствие вложенных объектов, и невозможность использования пулов памяти. Типичный пример из личного опыта – внутреннее представление программы в компиляторе.
Я не говорю, что невозможно разработать более безопасный язык программирования, лишённый большей части этих недостатков. Можно. Я сам работал на таком до прихода в MS. Плохо, что нынешняя CLR так бездарно разработана. Да что говорить, они умудрились наступить ровно на те же грабли с memory model, на которын наступила Java за несколько лет до того – причём в момент разработки CLR проблема была известна и вовсю обсуждалась.
Кстати, при написании програмы на таком безопасном языке надо учитывать и вновь возникающие проблемы. Пользовался ли кто-нибудь MS TV, где в течении нескольких секунд нельзя переключить каналы если идёт сборка мусора? Говорят, что впечатления незабываемы. Эту конкретную проблему они решили, достаточно обновить firmware. Но это очень хороший пример – уходя от одних проблем Вы напоретесь на другие. Реальных проблем managed код не решает, к примеру, безопасных средств синхронизации thread-ов в нём не появилось.

(3) Про переписывание «устаревшего» кода.
Немного я написал выше. Но у меня есть и значительно более яркий пример. Я имел счастье наблюдать (и частично участвовать) в переписывании не очень большого, но весьма сложного приложения, а именно compiler back-end.
Началось всё лет 5 назад, когда кого-то (не будем показывать пальцами) осенило, что в MS разрабатывается множество внутренних tools, которые имеют дело с трансформациями кода – компилятор, linker, BBT, profiler, JIT-ter, etc. При этом дублируется достаточно много кода. Родилась гениальная идея – давайте выкинем все наработки и напишем единую супер-систему с нуля. Разумеется, основой режим работы будет managed, хотя для совместимости (и производительности) можно будет скомпилировать систему в native код.
Работа началась, и ведётся уже 5+ лет.
Результаты:
• Имеется business unit из 50+ человек который активно работает с применением самых передовых технологий (например, scrum)
• Разработка нынешнего back-end заморожена; в VS9 будет выпущен фактически тот же back-end, что и в VS8, с починкой самых серьёзных ошибок (silent bad code, и то не все); просьбы починить ошибки, от починки которых стало бы лучше всему MS – например, сделать лучшие stack dumps – отвергаются – «нет ресурсов»
• На протяжении последних 3-4 лет практически все запросы внешних клиентов и большинство запросов внутренних добавить те или иные возможности к существующему back-end отвергаются – «нет ресурсов»
• Новый back-end дебютирует в VS10 (не VS9, который ещё не вышел), причём только для одной платформы (из 3-х), и будет поддерживать не все возможности существующего; если пользователь попробует воспользоваться отсутствующими возможностями, будет молча запущен старый back-end
• Предполагается, что качество сгенерированного кода будет примерно таким же, каким оно было у старого back-end-a в момент конца активной разработки; т.е. в 2008 году планируется достигнуть уровень 2002-2003 года; у меня есть большие сомнения на этот счёт
Выводы:
• У MS слишком много денег
• Внутренним customer-ам деваться от VC некуда, съедят всё, что им дадут
• Внешние customer-ы покупают Visual Studio не из-за качества С++ компилятора, иначе все давно ушли бы к конкурентам (например, на Intel C++)
• Впрочем те клиенты, кто могут, активно уходят к Intel-у
• У Visual C++ сейчас репутация «типичного MS продукта», и она всё ухудшается – особенно на фоне описанных ранее проблем с IDE и широкой рекламной кампании CLR/managed tools (более трети customer-ов искренне считает, что MS прекратил разработку native tools)
Я искренне надеюсь, что описанная ситуация не будет повторена в отделении, которое напрямую приносит деньги MS. Впрочем, судя по попыткам сделать нечто подобное с Windows – WinFS, managed shell и пр. – мои надежды безосновательны.