2015-04-20 17 views
6

Mam projekt, który wykorzystuje sporo metaprogramowania szablonu C++. To sprawia, że ​​czas kompilacji jest długi. Rozumiem, że nie mogę mieć ciasta i jeść go, ale chciałbym poznać kilka wskazówek i porad dotyczących zmniejszania czasu kompilacji. Próbowałem już jawnych instancji i chociaż w niektórych przypadkach może to pomóc, wiele razy instancje są unikalne dla konkretnej jednostki kompilacji, w którym to przypadku jawne tworzenie instancji nic nie pomoże. A teraz mówimy tylko o Clangu, który wykonuje całkiem niezłą robotę. Kiedy próbuję tego w G ++, czas kompilacji właśnie wybucha. W przypadku jednego pliku przestałem czekać na kompilację po 45 minutach.Co jest częstym winowajcą powolności TMP

  • Czy są jakieś powody, jeśli chodzi o meta-programowanie szablonowe, o których wiadomo, że często stanowią problem? Jakich technik należy unikać i co powinienem zrobić?
  • Czy istnieją obszary, w których GCC jest znane z tego, że działa gorzej niż Clang i czy istnieje sposób obejścia tego problemu?

Używam głównie prostych technik waniliowych C++ 11, nie używam Boost MPL lub podobnych bibliotek.

Odpowiedz

0

W naszych projektach używaliśmy jedynie myślenia i prób. To znaczy. najpierw myślimy "jakie są tutaj złożone szablony", a następnie próbowaliśmy wyizolować te szablony lub usunąć je lub refaktor, aby sprawdzić, czy zmiany czasu kompilacji. Często czas kompilacji szablonów towarzyszy zwiększone wykorzystanie pamięci, nawet zgłosiłem jeden błąd gcc w tej sprawie (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54056).

Jest jeszcze jedna sztuczka, która pomogła kilka razy, używając przełącznika wiersza polecenia -Q (pokaż funkcje aktualnie kompilowane przez gcc). Na przykład. dla błędu związanego powyżej było jasne, że gcc spowolnił te błędne szablony.

2

Oto kilka porad dotyczących metaprogramowanie z C++ 11 i poza nią:

  • Wolę algorytmów opartych o zmiennej liczbie argumentów ekspansja. Szablony Variadic są zwykle obsługiwane szybko przez kompilator w porównaniu z łańcuchem O (n) instancji szablonów, które zwykle są potrzebne dla typelistów i powiązane ze starym C++ 98/03. Bardzo chciałbym zobaczyć wyrażenia C++ 1z fold, jako metodę implementowania metafunkcji rodziny fold przy użyciu rozszerzenia paczki.

  • łańcuchy Unikać spadkowe: Algorytmy oparte na rekurencyjnym dziedziczenia zwykle wykonywać źle ponieważ kompilator powinien śledzić metadane drzewa dziedziczenia. Preferuj nieprzetworzone wywołania do następnego numeru ::type zamiast dziedziczenia bezpośrednio z następnego "wywołania" jako skrótu, aby uzyskać ten element członkowski.

  • Wolę dziedziczenia dodatek do rekurencyjnego dziedziczenia: To znaczy, jeśli wdrażają krotki jak rzeczy, wolą

    template<typename... Ts> 
    struct tuple : Ts... 
    

    do

    template<typename Head, typename... Tail> 
    struct tuple : Head, tuple<Tail...> 
    

    ponieważ kompilator powinien intantiate N podtypy na tym ostatnim, plus narzut spadkowy opisany w punkcie powyżej.

  • Preferowane algorytmy oparte na wyszukiwaniu nazw: Wyszukiwanie nazw zwykle wykonuje się szybciej niż powtarzanie szablonów.Rozważmy więc zrobienie czegoś takiego, jak decltype(declval<T>().f()), aby obliczyć typ, w którym wynikiem jest prawidłowe f przeładowanie.

+0

Niestety, to są rzeczy, które już robię. Niektórymi rzeczami, które naprawdę zwiększyłem czasy kompilacji, było użycie 'std :: make_shared' i' std :: shared_ptr'. Zastąpiłem je własnymi odwołaniami liczącymi używając 'std :: atomic', ponieważ i tak robiłem typ kasowania. –

+0

@EmilEriksson Możliwe jest nadal używanie 'std :: shared_ptr' i nie dostaniesz zbyt dużo dodatkowych kosztów http://blog2.emptycrate.com/content/template-code-bloat-revisited-smaller-makehared – lefticus

+0

W tym przypadku nawet jeśli zmniejszyłem liczbę wystąpień 'std :: shared_ptr', nadal miałbym ich zbyt dużo i' std :: shared_ptr' jest droższy w tworzeniu instancji niż moja własna implementacja. Oczywiście, z dobrego powodu jest to kosztowne, że wymagana jest elastyczność w przypadku standardowej klasy biblioteki, która będzie używana wszędzie. Ale mam bardzo konkretny przypadek użycia i dzięki temu udało mi się skrócić czasy kompilacji za pomocą innego rozwiązania. –