Как один линт Clippy ускорили в 3133 раза
Линт clippy::nonstandard_macro_braces следит за тем, чтобы макросы вызывались с правильными скобками. В Rust пустой вектор создают через vec![], но формально ничто не мешает написать vec!() или даже vec! {"???"}. Такой код раздражает всех, кто его читает, поэтому Clippy для ряда известных макросов хранит «канонический» вид скобок и подсказывает разработчику, когда тот отступает от нормы.
Почему это было медленно
Проблема в том, что Clippy работает уже после раскрытия макросов. Вместо println! {"..."} он видит развёрнутый код вроде std::io::_print(std::format_args_nl!("Hello, world!")), и по нему невозможно понять, какие скобки стоял в исходнике. Rust не хранит явной карты вызовов макросов — по признанию автора, это одна из главных болей Clippy.
Чтобы восстановить исходные скобки, линт поднимался вверх по цепочке раскрытия, обращался к «глобальным данным сессии» с информацией о гигиене макросов, доставал по спану исходный текст и уже строковыми манипуляциями (разбить по !, обрезать, посмотреть на первый символ) выяснял, что за скобка использовалась.
Звучит терпимо — пока не выясняется, что вся эта процедура запускалась для каждого выражения, оператора и элемента во всём проекте. Каждый раз она дважды обращалась к данным гигиены, блокировала интернер символов и запускала рекурсию. То есть фактически тормозила весь компилятор ради проверки, которая в итоге отъедала около 25% времени работы Clippy.
«Виноваты сопровождающие»
Автор специально подчёркивает: это не ошибка конкретного контрибьютора и винить его неправильно. Ответственность лежит на мейнтейнерах, чья задача — сделать написание плохого кода максимально трудным. Rust избавляет от переполнений буфера и use-after-free, но это иногда означает, что придётся писать больше кода, реже прибегать к макросам и не увлекаться абстракциями настолько, чтобы «сотню раз виденная» функция незаметно съедала четверть времени работы.
Решение
Исправление уложилось менее чем в 200 строк: проблемную функцию переписали из пост-раскрывающего линта в пре-раскрывающий. Больше не нужно доставать исходный текст и вычислять спан скобок арифметикой, не нужно блокировать ни интернер символов, ни глобальные данные сессии. Автор честно признаёт, что работа с кодом до раскрытия макросов в Clippy считается хаком, которому не стоит доверять, — но этот хак экономит сотни тысяч «вычислительных долларов».
В довершение появился и давно задуманный сервер для бенчмарков — самостоятельно размещённый, с памятью на 200 дней и на распространённой архитектуре процессора, так что цифры близки к реальному пользовательскому опыту. Построить его удалось благодаря контракту с Rust Foundation.
Источник: Lobsters
Комментарии
Войдите, чтобы комментировать.