Кто из вас использовал сторонние библиотеки при написании кода? Вопрос риторический, ведь без использования сторонних библиотек разработка некоторых продуктов затянулась бы на очень и очень долгое время, ведь для решения каждой проблемы пришлось бы «изобретать велосипед».
Однако, помимо преимуществ, у использования сторонних библиотек есть и недостатки.
Один из таких недостатков недавно коснулся анализатора PVS-Studio для C#.
Анализатор долго не мог закончить анализ большого проекта из-за использования метода SymbolFinder.FindReferencesAsync из Roslyn API в диагностике V3083.
Жизнь в PVS-Studio, как всегда, шла своим чередом.
Были разработаны новые диагностики, усовершенствован статический анализатор, написаны новые статьи.
Внезапно! У одного из пользователей нашего анализатора в своем большом проекте анализ шел целый день и не смог его завершить.
Тревога! Тревога! Все руки на палубе! А мы свистнули, получили дампы от пользователя и начали разбираться в причинах долгого анализа.
Детальное изучение проблемы выявило, что дольше всех работала 3 диагностики C#.
Один из них оказался с диагностическим номером V3083. К этому диагнозу уже было повышенное внимание, но пришло время предпринимать конкретные действия.
V3083 предупреждает о неправильных вызовах событий C#.
Например, в коде:
V3083 будет указывать вызовы обработчиков событий.public class IncorrectEventUse { public event EventHandler EventOne; protected void InvokeEventTwice(object o, Eventers args) { if (EventOne != null) { EventOne(o, args); EventOne.Invoke(o, args); } } }
EventOne в методе InvokeEventTwice .
Подробнее о причинах опасности этого кода вы можете узнать в документация этот диагноз.
Внешне логика V3083 очень проста:
- найти вызов события;
- проверьте, правильно ли вызвано это событие;
- выдать предупреждение, если событие возникло неправильно.
Причина замедления
На самом деле логика немного сложнее.V3083 в каждом файле для каждого типа создает только один триггер анализатора на одно событие, куда записывает номера всех строк (для навигации в различных плагинах: Визуальная Студия , Райдер , СонарКуб ), где событие возникает неправильно.
Оказывается, первое, что вам нужно сделать, это найти все места, где вызывается событие.
Для подобной задачи в Roslyn API уже есть метод SymbolFinder.FindReferencesAsync , который использовался в V3083, чтобы не «изобретать велосипед».
Этот метод рекомендуется использовать во многих руководствах: первый , второй , третий и т. д. Возможно, в некоторых простых случаях скорости работы этого метода будет достаточно.
Однако чем больше кодовая база проекта, тем дольше этот метод будет работать.
Мы в этом на 100% убедились только после замены V3083.
Ускорение V3083 после изменений
При изменении диагностического кода или ядра анализатора необходимо убедиться, что ничего из того, что работало ранее, не сломалось.Для этого у нас есть положительные и отрицательные тесты по каждой диагностике, юнит-тесты ядра анализатора, а также база проектов с открытым исходным кодом (которых уже почти 90).
Зачем нам нужна база данных проектов с открытым исходным кодом? Мы запускаем на нем наш анализатор, чтобы протестировать его в «боевых условиях», а еще этот прогон служит дополнительной проверкой того, что мы ничего не сломали в анализаторе.
Перед изменением V3083 у нас уже был запущен анализатор на этой базе.
Остается только сделать аналогичный прогон после замены V3083 и узнать выигрыш во времени.
Результаты нас приятно удивили.
Без использования SymbolFinder.FindReferencesAsync в V3083 мы получили ускорение на 9% в тестах.
Если кому-то эти цифры показались незначительными, вот характеристики компьютера, на котором проводились измерения:
Думаю, после этого даже самые упорные скептики убедились в масштабах проблемы, тихо и мирно жившей в диагнозе V3083.
Заключение
Пусть эта заметка станет предупреждением для всех, кто использует Roslyn API! И вы не повторите наших ошибок.Причем это касается не только метода SymbolFinder.FindReferencesAsync , но и все остальные методы класса Microsoft.CodeAnaанализ.
FindSymbols.SymbolFinder , которые используют тот же механизм.
Также советую всем разработчикам внимательнее и тщательнее изучать используемые вами библиотеки.
Я говорю это не просто так! Чтобы понять, почему это так важно, советую изучить две другие наши заметки: первый , второй .
Они обсуждают этот вопрос более подробно.
Помимо диагностики мы взялись за другие оптимизации анализатора PVS-Studio, о которых поговорим в следующих статьях и заметках.
Диагностическое изменение V3083 еще не выпущено, поэтому версия анализатора 7.12 работает с использованием SymbolFinder.FindReferencesAsync .
Как уже говорилось ранее, замедление работы анализатора было обнаружено еще в двух C#-диагностиках, кроме V3083. Ради интереса предлагаю читателям оставить в комментариях свои догадки о том, что это за диагностики.
Когда будет более 50 предположений, я приоткрою завесу тайны и назову цифры этих диагностик.
Если вы хотите поделиться этой статьей с англоязычной аудиторией, воспользуйтесь ссылкой для перевода: Валерий Комаров.
Roslyn API: почему PVS-Studio так долго анализировал проект .
Теги: #Управление разработкой #api #pvs-studio #csharp #pvs #статический анализ кода #статический анализатор кода #pvs-studio бесплатно #pvs-studio бесплатно
-
Действительно
19 Oct, 24 -
Облегченная Криптография Интернета Вещей
19 Oct, 24 -
В Поисках Утраченной Эффективности
19 Oct, 24