Finalización de código más rápida con clang

108

Estoy investigando posibles aceleraciones de finalización de código mientras uso el mecanismo de finalización de código de clang. El flujo que se describe a continuación es lo que encontré en rtags , de Anders Bakken.

Las unidades de traducción se analizan mediante un demonio que supervisa los archivos en busca de cambios. Esto se realiza mediante clang_parseTranslationUnitfunciones llamadas y relacionadas ( reparse*, dispose*). Cuando el usuario solicita que se complete una línea y columna determinadas en un archivo de origen, el demonio pasa la unidad de traducción en caché para la última versión guardada del archivo de origen y el archivo de origen actual a clang_codeCompleteAt. ( Documentos Clang CodeComplete ).

Las banderas pasadas a clang_parseTranslationUnit(de CompletionThread :: process, línea 271 ) son CXTranslationUnit_PrecompiledPreamble|CXTranslationUnit_CacheCompletionResults|CXTranslationUnit_SkipFunctionBodes. Las banderas pasadas a clang_codeCompleteAt(de CompletionThread :: process, línea 305 ) son CXCodeComplete_IncludeMacros|CXCodeComplete_IncludeCodePatterns.

La llamada a clang_codeCompleteAtes muy lenta: toma alrededor de 3-5 segundos obtener una finalización incluso en los casos en que la ubicación de finalización es un código de acceso de miembro legítimo, un subconjunto del caso de uso previsto mencionado en la documentación de clang_codeCompleteAt. Esto parece demasiado lento para los estándares de finalización de código IDE. ¿Hay alguna forma de acelerar esto?

Pradhan
fuente
8
Estaría encantado de ayudarlo, pero necesitamos más detalles. El código de ejemplo sería bueno para empezar
raph.amiard
1
Silbido. ¿Hay algún progreso en este problema?
Mehrwolf
4
@Cameron Perdón por la larga demora en responderle. He intentado todas las combinaciones de 8 CXTranslationUnit_SkipFunctionBodies, CXCodeComplete_IncludeMacros, CXCodeComplete_IncludeCodePatternsy no ver una diferencia significativa en la base de código que estoy trabajando con. Todos ellos promedian alrededor de 4 segundos por completo. Supongo que esto se debe solo al tamaño de las unidades de traducción. CXTranslationUnit_PrecompiledPreambleasegura reparseTUes muy rápido. Sin embargo, incluso con CXTranslationUnit_CacheCompletionResults, clang_codeCompleteAtes dolorosamente lento para mi caso de uso.
Pradhan
1
@Mehrwolf Ack. Vea el comentario anterior.
Pradhan
7
Hmm, eso es lamentable. ¿Puede reproducir la lentitud de finalización en una unidad de traducción disponible para el público (por ejemplo, código abierto)? Ayudaría si pudiéramos reproducir esto nosotros mismos. La finalización debería ser aproximadamente tan rápida como el análisis, ya que eso es lo que hace internamente (inyecta un token de finalización de código especial y analiza hasta ese punto).
Cameron

Respuestas:

6

El problema que tiene clang_parseTranslationUnit es que el preámbulo precompilado no se reutiliza la segunda vez que se llama finalización de código. Calcular el preámbulo precompilado toma más del 90% de este tiempo, por lo que debe permitir que el preámbulo precompilado se reutilice lo antes posible.

De forma predeterminada, se reutiliza la tercera vez que se llama para analizar / analizar la unidad de traducción.

Eche un vistazo a esta variable 'PreambleRebuildCounter' en ASTUnit.cpp.

Otro problema es que este preámbulo se guarda en un archivo temporal. Puede mantener el preámbulo precompilado en la memoria en lugar de un archivo temporal. Sería más rápido. :)

GutiMac
fuente
¡Increíble! Parece que llega al problema real. Echaré un vistazo a esto y te lo haré saber. ¡Gracias!
Pradhan
¡Okay! avíseme si funciona para usted! y si tienes alguna duda no dudes en preguntarme !!!!
GutiMac
4

A veces, los retrasos de esta magnitud se deben a tiempos de espera en los recursos de red (recursos compartidos de NFS o CIFS en una ruta de búsqueda de archivos o sockets). Intente monitorear el tiempo que cada llamada al sistema tarda en completarse prefijando el proceso con el que se ejecuta strace -Tf -o trace.out. Mire los números entre paréntesis angulares trace.outpara la llamada al sistema que tarda mucho en completarse.

También puede monitorear el tiempo entre llamadas al sistema para ver qué procesamiento de un archivo tarda demasiado en completarse. Para hacer esto, prefija el proceso con el que se ejecuta strace -rf -o trace.out. Mire el número antes de cada llamada al sistema para buscar intervalos largos de llamadas al sistema. Vaya hacia atrás desde ese punto buscando openllamadas para ver cuál era el archivo que se estaba procesando.

Si esto no ayuda, puede crear un perfil de su proceso para ver dónde pasa la mayor parte del tiempo.

Diomidis Spinellis
fuente