Более быстрое завершение кода с помощью clang

108

Я исследую потенциальное ускорение завершения кода при использовании механизма завершения кода clang. Описанный ниже поток - это то, что я нашел в rtags Андерса Баккена.

Единицы перевода анализируются демоном, отслеживающим файлы на предмет изменений. Это делается с помощью вызываемых clang_parseTranslationUnitи связанных функций ( reparse*, dispose*). Когда пользователь запрашивает завершение для данной строки и столбца в исходном файле, демон передает кэшированную единицу перевода для последней сохраненной версии исходного файла и текущего исходного файла в clang_codeCompleteAt. ( Документы Clang CodeComplete ).

Флаги , передаваемые clang_parseTranslationUnit(от CompletionThread :: процесса, строка 271 ) являются CXTranslationUnit_PrecompiledPreamble|CXTranslationUnit_CacheCompletionResults|CXTranslationUnit_SkipFunctionBodes. Флаги , передаваемые clang_codeCompleteAt(от CompletionThread :: процесса, строка 305 ) являются CXCodeComplete_IncludeMacros|CXCodeComplete_IncludeCodePatterns.

Вызов clang_codeCompleteAtвыполняется очень медленно - для получения завершения требуется около 3-5 секунд даже в тех случаях, когда местом завершения является допустимый код доступа к члену, подмножество предполагаемого варианта использования, упомянутого в документации clang_codeCompleteAt. Это кажется слишком медленным по стандартам завершения кода IDE. Есть ли способ ускорить это?

Прадхан
источник
8
Я был бы рад помочь вам, но нам нужно больше подробностей. Пример кода будет хорош для начала
raph.amiard
1
Пинг. Есть ли прогресс по этой проблеме?
Mehrwolf
4
@Cameron Извините за долгую задержку с ответом. Я попробовал все 8 комбинаций CXTranslationUnit_SkipFunctionBodies, CXCodeComplete_IncludeMacros, CXCodeComplete_IncludeCodePatternsи не вижу существенную разницу на кодовом я работаю с. Все они в среднем составляют около 4 секунд на выполнение. Я предполагаю, что это просто из-за размера ЕП. CXTranslationUnit_PrecompiledPreambleгарантирует reparseTUочень быстро. Однако даже с CXTranslationUnit_CacheCompletionResults, clang_codeCompleteAtмучительно медленно для моего случая использования.
Прадхан
1
@Mehrwolf Ack. См. Комментарий выше.
Прадхан
7
Хм, это прискорбно. Можете ли вы воспроизвести медленное завершение в общедоступной единице перевода (например, с открытым исходным кодом)? Было бы полезно, если бы мы могли воспроизвести это сами. Завершение должно быть примерно таким же быстрым, как и повторный анализ, поскольку это то, что он делает внутри (он вводит специальный токен завершения кода и выполняет синтаксический анализ до этого момента).
Кэмерон

Ответы:

6

Проблема clang_parseTranslationUnit заключается в том, что предварительно скомпилированная преамбула не используется повторно во второй раз, который называется завершением кода. Вычисление преамбулы прекомпиляции занимает более 90% этого времени, поэтому вы должны позволить, чтобы прекомпилированная преамбула была повторно использована как можно скорее.

По умолчанию он повторно используется в третий раз, который вызывается для синтаксического анализа / повторного анализа единицы перевода.

Взгляните на эту переменную PreambleRebuildCounter в ASTUnit.cpp.

Другая проблема заключается в том, что эта преамбула сохраняется во временном файле. Вы можете сохранить предварительно скомпилированную преамбулу в памяти вместо временного файла. Быстрее бы. :)

GutiMac
источник
Потрясающие! Похоже, дело доходит до реальной проблемы. Взглянем на это и дам вам знать. Спасибо!
Pradhan
хорошо! дайте мне знать, если это сработает для вас! и если у вас есть вопросы, не стесняйтесь спрашивать меня !!!!
GutiMac
4

Иногда задержки такого размера возникают из-за тайм-аутов сетевых ресурсов (общих ресурсов NFS или CIFS на пути поиска файлов или сокетах). Попробуйте отслеживать время выполнения каждого системного вызова, добавив префикс процесса, которым вы запускаете strace -Tf -o trace.out. Посмотрите на числа в угловых скобках trace.outдля системного вызова, для выполнения которого требуется много времени.

Вы также можете отслеживать время между системными вызовами, чтобы увидеть, какая обработка файла занимает слишком много времени. Для этого добавьте префикс к процессу strace -rf -o trace.out. Посмотрите на номер перед каждым системным вызовом, чтобы найти длинные интервалы между системными вызовами. Вернитесь назад от этой точки, ища openвызовы, чтобы увидеть, какой файл обрабатывается.

Если это не помогает, вы можете профилировать свой процесс, чтобы увидеть, на что он тратит большую часть своего времени.

Диомидис Спинеллис
источник