Szybsze uzupełnianie kodu dzięki clang

108

Badam potencjalne przyspieszenia uzupełniania kodu podczas korzystania z mechanizmu uzupełniania kodu Clang. Przepływ opisany poniżej jest tym, co znalazłem w rtagach autorstwa Andersa Bakkena .

Jednostki tłumaczeniowe są analizowane przez demona monitorujące pliki pod kątem zmian. Robią to wywołane clang_parseTranslationUniti powiązane funkcje ( reparse*, dispose*). Gdy użytkownik zażąda uzupełnienia w danej linii i kolumnie w pliku źródłowym, demon przekazuje buforowaną jednostkę tłumaczeniową dla ostatnio zapisanej wersji pliku źródłowego i bieżącego pliku źródłowego do clang_codeCompleteAt. ( Dokumenty Clang CodeComplete ).

Flagi przekazywane do clang_parseTranslationUnit(z CompletionThread :: process, wiersz 271 ) to CXTranslationUnit_PrecompiledPreamble|CXTranslationUnit_CacheCompletionResults|CXTranslationUnit_SkipFunctionBodes. Flagi przekazane do clang_codeCompleteAt(z CompletionThread :: process, wiersz 305 ) to CXCodeComplete_IncludeMacros|CXCodeComplete_IncludeCodePatterns.

Wywołanie clang_codeCompleteAtjest bardzo powolne - uzyskanie zakończenia zajmuje około 3-5 sekund, nawet w przypadkach, gdy lokalizacją zakończenia jest prawidłowy kod dostępu członka, podzbiór zamierzonego przypadku użycia wymieniony w dokumentacji clang_codeCompleteAt. Wydaje się to zbyt wolne w świetle standardów uzupełniania kodu IDE. Czy jest sposób, aby to przyspieszyć?

Pradhan
źródło
8
Chętnie pomogę, ale potrzebujemy więcej szczegółów. Przykładowy kod byłby dobry na początek
raph.amiard
1
Świst. Czy jest jakiś postęp w tym problemie?
Mehrwolf
4
@Cameron Przepraszamy za długie opóźnienie w skontaktowaniu się z Tobą. Próbowałem wszystkich kombinacji 8 CXTranslationUnit_SkipFunctionBodies, CXCodeComplete_IncludeMacros, CXCodeComplete_IncludeCodePatternsi nie zobaczyć znaczną różnicę w kodzie pracuję z. Wszystkie z nich mają średnio około 4 sekund na ukończenie. Wydaje mi się, że dzieje się tak tylko z powodu rozmiaru jednostek tłumaczeniowych. CXTranslationUnit_PrecompiledPreamblezapewnia, że reparseTUjest bardzo szybki. Jednak nawet z CXTranslationUnit_CacheCompletionResults, clang_codeCompleteAtjest boleśnie powolny w moim przypadku użycia.
Pradhan
1
@Mehrwolf Ack. Patrz powyższy komentarz.
Pradhan
7
Hmm, to niefortunne. Czy możesz odtworzyć powolne zakończenie w jednostce tłumaczeniowej dostępnej publicznie (np. Open source)? Pomogłoby, gdybyśmy byli w stanie to odtworzyć sami. Uzupełnianie powinno być mniej więcej tak szybkie, jak ponowna analiza, ponieważ to właśnie robi wewnętrznie (wstrzykuje specjalny token ukończenia kodu i analizuje do tego momentu).
Cameron

Odpowiedzi:

6

Problem, który ma clang_parseTranslationUnit polega na tym, że prekompilowana preambuła nie jest ponownie używana za drugim razem, co jest nazywane uzupełnianiem kodu. Oblicz, że prekompilowana preambuła zajmuje więcej niż 90% tego czasu, więc powinieneś pozwolić, aby prekompilowana preambuła została ponownie wykorzystana tak szybko, jak to możliwe.

Domyślnie jest ponownie używany po raz trzeci, gdy jest wywoływany w celu przeanalizowania / ponownej analizy jednostki tłumaczeniowej.

Przyjrzyj się tej zmiennej „PreambleRebuildCounter” w ASTUnit.cpp.

Innym problemem jest to, że ta preambuła jest zapisywana w pliku tymczasowym. Możesz zachować prekompilowaną preambułę w pamięci zamiast w pliku tymczasowym. Byłoby szybciej. :)

GutiMac
źródło
Niesamowite! Wygląda na to, że chodzi o prawdziwy problem. Przyjrzę się temu i dam Ci znać. Dzięki!
Pradhan
dobrze! daj mi znać, czy to działa dla Ciebie! a jeśli masz jakieś pytania, zapytaj mnie !!!!
GutiMac
4

Czasami opóźnienia tej wielkości są spowodowane przekroczeniem limitu czasu zasobów sieciowych (udziałów NFS lub CIFS na ścieżce wyszukiwania plików lub gniazdach). Spróbuj monitorować czas potrzebny do zakończenia każdego wywołania systemowego, poprzedzając proces, z którym uruchomiłeś strace -Tf -o trace.out. Spójrz na liczby w nawiasach ostrych, trace.outaby sprawdzić wywołanie systemowe, które zajmuje dużo czasu.

Możesz także monitorować czas między wywołaniami systemowymi, aby sprawdzić, które przetwarzanie pliku trwa zbyt długo. Aby to zrobić, poprzedź proces, z którym uruchamiasz strace -rf -o trace.out. Spójrz na numer przed każdym wywołaniem systemowym, aby znaleźć długie interwały wywołań systemowych. Cofnij się od tego punktu, szukając openwywołań, aby zobaczyć, który plik był przetwarzany.

Jeśli to nie pomoże, możesz sprofilować swój proces, aby zobaczyć, gdzie spędza większość czasu.

Diomidis Spinellis
źródło