Fin de code plus rapide avec clang

108

J'étudie les accélérations potentielles de complétion de code tout en utilisant le mécanisme de complétion de code de clang. Le flux décrit ci-dessous est ce que j'ai trouvé dans rtags , par Anders Bakken.

Les unités de traduction sont analysées par un démon surveillant les fichiers pour les changements. Ceci est fait par clang_parseTranslationUnitles fonctions appelées et associées ( reparse*, dispose*). Lorsque l'utilisateur demande une complétion à une ligne et une colonne données dans un fichier source, le démon transmet l'unité de traduction mise en cache pour la dernière version enregistrée du fichier source et le fichier source actuel à clang_codeCompleteAt. ( Clang CodeComplete docs ).

Les indicateurs passés à clang_parseTranslationUnit(de CompletionThread :: process, ligne 271 ) sont CXTranslationUnit_PrecompiledPreamble|CXTranslationUnit_CacheCompletionResults|CXTranslationUnit_SkipFunctionBodes. Les indicateurs passés à clang_codeCompleteAt(de CompletionThread :: process, ligne 305 ) sont CXCodeComplete_IncludeMacros|CXCodeComplete_IncludeCodePatterns.

L'appel à clang_codeCompleteAtest très lent - il faut environ 3 à 5 secondes pour obtenir un achèvement, même dans les cas où l'emplacement d'achèvement est un code d'accès membre légitime, un sous-ensemble du cas d'utilisation prévu mentionné dans la documentation de clang_codeCompleteAt. Cela semble bien trop lent par rapport aux normes de complétion de code IDE. Y a-t-il un moyen d'accélérer cela?

Pradhan
la source
8
Je serais heureux de vous aider mais nous avons besoin de plus de détails. Un exemple de code serait bon pour commencer
raph.amiard
1
Ping. Y a-t-il des progrès sur ce problème?
Mehrwolf
4
@Cameron Désolé pour le long délai pour vous répondre. J'ai essayé toutes les 8 combinaisons CXTranslationUnit_SkipFunctionBodies, CXCodeComplete_IncludeMacros, CXCodeComplete_IncludeCodePatternset ne voit pas de différence significative sur la base de code , je travaille avec. Tous en moyenne environ 4 secondes par complet. Je suppose que c'est juste à cause de la taille des UT. CXTranslationUnit_PrecompiledPreambleassure reparseTUest très rapide. Cependant, même avec CXTranslationUnit_CacheCompletionResults, clang_codeCompleteAtc'est douloureusement lent pour mon cas d'utilisation.
Pradhan
1
@Mehrwolf Ack. Voir le commentaire ci-dessus.
Pradhan
7
Hmm, c'est malheureux. Pouvez-vous reproduire la lenteur de réalisation sur une unité de traduction accessible au public (par exemple open source)? Cela aiderait si nous pouvions reproduire cela nous-mêmes. L'achèvement devrait être à peu près aussi rapide que l'analyse, car c'est ce qu'il fait en interne (il injecte un jeton d'achèvement de code spécial et analyse jusqu'à ce point).
Cameron

Réponses:

6

Le problème de clang_parseTranslationUnit est que le préambule précompilé n'est pas réutilisé la deuxième fois que l'on appelle l'achèvement du code. Le calcul du préambule précompilé prend plus de 90% de ce temps, vous devez donc permettre que le préambule précompilé soit réutilisé dès que possible.

Par défaut, il est réutilisé la troisième fois qu'il est appelé pour analyser / analyser l'unité de traduction.

Jetez un œil à cette variable «PreambleRebuildCounter» dans ASTUnit.cpp.

Un autre problème est que ce préambule est enregistré dans un fichier temporaire. Vous pouvez conserver le préambule précompilé en mémoire au lieu d'un fichier temporaire. Ce serait plus rapide. :)

GutiMac
la source
Impressionnant! Cela ressemble à un problème réel. Jettera un oeil à ceci et vous le fera savoir. Merci!
Pradhan
D'accord! Dites-moi si cela marche pour vous! et si vous avez des questions, n'hésitez pas à me les poser !!!!
GutiMac
4

Parfois, des retards de cette ampleur sont dus à des délais d'expiration sur les ressources réseau (partages NFS ou CIFS sur un chemin de recherche de fichier ou des sockets). Essayez de surveiller le temps nécessaire à chaque appel système en préfixant le processus avec lequel vous exécutez strace -Tf -o trace.out. Regardez les nombres entre crochets trace.outpour l'appel système qui prend beaucoup de temps.

Vous pouvez également surveiller le temps entre les appels système pour voir quel traitement d'un fichier prend trop de temps. Pour ce faire, préfixez le processus avec lequel vous exécutez strace -rf -o trace.out. Regardez le numéro avant chaque appel système pour rechercher de longs intervalles d'appels système. Revenez en arrière à partir de ce point à la recherche d' openappels pour voir quel fichier était en cours de traitement.

Si cela ne vous aide pas, vous pouvez profiler votre processus pour voir où il passe la plupart de son temps.

Diomidis Spinellis
la source