Conclusão de código mais rápida com clang

108

Estou investigando possíveis acelerações de conclusão de código ao usar o mecanismo de conclusão de código do clang. O fluxo descrito abaixo é o que encontrei no rtags , de Anders Bakken.

As unidades de tradução são analisadas por um daemon que monitora arquivos para alterações. Isso é feito por clang_parseTranslationUnitfunções chamadas e relacionadas ( reparse*, dispose*). Quando o usuário solicita o preenchimento de uma determinada linha e coluna em um arquivo de origem, o daemon passa a unidade de tradução em cache da última versão salva do arquivo de origem e do arquivo de origem atual para clang_codeCompleteAt. ( Documentos do Clang CodeComplete ).

Os sinalizadores passados ​​para clang_parseTranslationUnit(de CompletionThread :: process, linha 271 ) são CXTranslationUnit_PrecompiledPreamble|CXTranslationUnit_CacheCompletionResults|CXTranslationUnit_SkipFunctionBodes. Os sinalizadores passados ​​para clang_codeCompleteAt(de CompletionThread :: process, linha 305 ) são CXCodeComplete_IncludeMacros|CXCodeComplete_IncludeCodePatterns.

A chamada para clang_codeCompleteAté muito lenta - leva cerca de 3-5 segundos para obter uma conclusão, mesmo nos casos em que o local de conclusão é um código de acesso de membro legítimo, um subconjunto do caso de uso pretendido mencionado na documentação de clang_codeCompleteAt. Isso parece muito lento para os padrões de conclusão de código IDE. Existe uma maneira de acelerar isso?

Pradhan
fonte
8
Ficaria feliz em ajudá-lo, mas precisamos de mais detalhes. Um exemplo de código seria bom para um começo
raph.amiard
1
Ping. Existe algum progresso neste problema?
Mehrwolf
4
@Cameron Desculpe pela demora em entrar em contato com você. Eu tentei todos os 8 combinações de CXTranslationUnit_SkipFunctionBodies, CXCodeComplete_IncludeMacros, CXCodeComplete_IncludeCodePatternse não viu uma diferença significativa na base de código que eu estou trabalhando. Todos eles em média cerca de 4 segundos por completo. Acho que isso se deve ao tamanho das TUs. CXTranslationUnit_PrecompiledPreamblegarante reparseTUé muito rápido. No entanto, mesmo com CXTranslationUnit_CacheCompletionResults, clang_codeCompleteAté dolorosamente lento para meu caso de uso.
Pradhan
1
@Mehrwolf Ack. Veja o comentário acima.
Pradhan
7
Hmm, isso é lamentável. Você pode reproduzir a lentidão de conclusão em uma unidade de tradução disponível ao público (por exemplo, código aberto)? Ajudaria se fôssemos capazes de reproduzir isso nós mesmos. A conclusão deve ser quase tão rápida quanto a nova análise, já que é isso que ela faz internamente (ela injeta um token de conclusão de código especial e analisa até esse ponto).
Cameron,

Respostas:

6

O problema que clang_parseTranslationUnit tem é que o preâmbulo pré-compilado não é reutilizado na segunda vez que é chamado de conclusão de código. Calcular o preâmbulo pré-compilado leva mais de 90% desse tempo, portanto, você deve permitir que o preâmbulo pré-compilado seja reutilizado assim que possível.

Por padrão, ele é reutilizado pela terceira vez que é chamado para analisar / reanalisar a unidade de tradução.

Dê uma olhada na variável 'PreambleRebuildCounter' em ASTUnit.cpp.

Outro problema é que este preâmbulo é salvo em um arquivo temporário. Você pode manter o preâmbulo pré-compilado na memória, em vez de em um arquivo temporário. Seria mais rápido. :)

GutiMac
fonte
Impressionante! Parece que chega ao verdadeiro problema. Vou dar uma olhada nisso e informá-lo. Obrigado!
Pradhan
Está bem! deixe-me saber se funciona para você! e se você tiver alguma dúvida sinta-se à vontade para me perguntar !!!!
GutiMac
4

Às vezes, atrasos dessa magnitude são devido a tempos limite nos recursos de rede (compartilhamentos NFS ou CIFS em um caminho de pesquisa de arquivo ou soquetes). Tente monitorar o tempo que cada chamada de sistema leva para ser concluída, prefixando o processo com o qual sua execução strace -Tf -o trace.out. Observe os números entre colchetes angulares trace.outpara a chamada do sistema que leva muito tempo para ser concluída.

Você também pode monitorar o tempo entre as chamadas do sistema para ver qual processamento de um arquivo leva muito tempo para ser concluído. Para fazer isso, prefixe o processo com o qual você executa strace -rf -o trace.out. Verifique o número antes de cada chamada do sistema para verificar se há intervalos longos de chamada do sistema. Volte a partir desse ponto procurando openchamadas para ver qual era o arquivo que estava sendo processado.

Se isso não ajudar, você pode criar um perfil de seu processo para ver onde ele passa a maior parte do tempo.

Diomidis Spinellis
fonte