13

Powiedzmy mam następujący metafunkcji:Optymalizacja wydajności w czasie kompilacji przez buforowanie metafunkcji

template <typename T> 
struct make_pair { 
    using type = std::pair< 
     typename std::remove_reference<T>::type, 
     typename std::remove_reference<T>::type 
    >; 
}; 

Czy to poprawić szybkość kompilacji to zrobić (lub coś innego) w zamian?

template <typename T> 
struct make_pair { 
    using without_reference = typename std::remove_reference<T>::type; 
    using type = std::pair<without_reference, without_reference>; 
}; 

widzę dwie możliwości:

  1. Kompilator musi popracować za każdym razem widzi typename std::remove_reference<T>::type. Używanie pośredniego aliasu ma pewien rodzaj zachowania "buforującego", które pozwala kompilatorowi wykonać tylko jedną pracę.

  2. Wydajność czasu kompilacji mierzona jest liczbą instancji szablonu, którą musi wykonać kompilator. Ponieważ std::remove_reference<T>::type odnosi się do tego samego typu co std::remove_reference<T>::type, w obu przypadkach wymagana jest tylko jedna instancja szablonu, więc obie implementacje są równoważne wydajności w czasie kompilacji WRT.

Myślę, że B ma rację, ale chciałbym być pewien. Jeśli odpowiedź okaże się odpowiednia dla kompilatora, byłbym głównie zainteresowany poznaniem odpowiedzi na Clang i GCC.

Edit:

I porównywana kompilację programu testowego mieć pewne dane pracować. Program badań robi coś takiego:

template <typename ...> struct result;  

template <typename T> 
struct with_cache { 
    using without_reference = typename std::remove_reference<T>::type; 
    using type = result<without_reference, ..., without_reference>; 
}; 

template <typename T> 
struct without_cache { 
    using type = result< 
     typename std::remove_reference<T>::type, 
     ..., 
     typename std::remove_reference<T>::type 
    >; 
{ }; 

using Result = with[out]_cache<int>::type; 

Oto średnie czasy dla 10 kompilacjach programu, z 10 000 parametrów szablonu w result<>.

   ------------------------- 
       | g++ 4.8 | clang++ 3.2 | 
----------------------------------------- 
| with cache | 0.1628s | 0.3036s  | 
----------------------------------------- 
| without cache | 0.1573s | 0.3785s  | 
----------------------------------------- 

Program testowy jest generowany przez skrypt dostępny here.

+4

Myślę, że żadne spekulacje nie zastąpią rzeczywistych pomiarów. Opublikujcie jakieś dane czasowe, a następnie możemy stworzyć ładną teorię, która je wyjaśni. –

+0

Widziałem dyskusję na temat klangów, która mówi, że tworzą hashtables dla instancji szablonów zamiast połączonych list. Nie wiem jednak, do kogo się porównują. –

+0

Kompilator 'szablonu', który nie dokonuje zapamiętywania, będzie śmiesznie wolny. – Yakk

Odpowiedz

2

Nie mogę powiedzieć, że tak jest w przypadku wszystkich kompilatorów, ale GCC i najprawdopodobniej każdy inny główny kompilator użyje funkcji zapamiętywania. Jeśli o tym pomyślisz, to prawie musi.

Rozważmy następujący kod

&f<X, Y>::some_value == &f<X, Y>::some_value 

Jest to konieczne, aby mogło być prawdziwe, to kompilator musi upewnić się, że nie powiela definicje metod i członków statycznych. Teraz mogą istnieć inne sposoby, aby to zrobić, ale to tylko krzyczy do mnie memo; Nie widzę innego sposobu, aby to wdrożyć nawet (przyznane, myślałem o tym bardzo ciężko)

Kiedy używam TMP, oczekuję wystąpienia memoizacji. Byłby to prawdziwy ból, gdyby nie, zbyt wolny. Jedyny sposób, w jaki widziałem poważne różnice w wydajności kompilacji, to: a) użycie szybszego kompilatora, takiego jak Clang (który jest 3 razy szybszy niż GCC) i wybór różnych algorytmów. Wydaje mi się, że małe stałe czynniki mają mniejszą wagę w TMP niż w C/C++. Wybierz odpowiedni algorytm, staraj się nie robić niepotrzebnej pracy, spróbuj ograniczyć liczbę instancji i korzystaj z dobrego kompilatora (MSVC++ to naprawdę powolny i daleki od zgodności z C++ 11, ale GCC i Clang są całkiem dobre); to wszystko, co możesz zrobić naprawdę.

Należy również poświęcić czas kompilacji dla lepszego kodu. Przedwczesna optymalizacja czasu kompilacji jest o wiele bardziej zła niż zwykła przedwczesna optymalizacja. Może istnieć wyjątek od tego, jeśli z jakiegoś powodu wydajność staje się masowo zaporowa dla rozwoju; Nigdy nie słyszałem o takim przypadku.

+1

Ta odpowiedź nie jest zła, ale tak naprawdę nie jest tym, czego szukałem. Szukam czegoś bardziej pewnego, jak potwierdzenie od dewelopera GCC lub Clanga. Powodem, dla którego zadałem to pytanie, było to, że pracowałem nad bibliotekami metaprogramowania i optymalizowałem czasy kompilacji, które są kluczowe. –

Powiązane problemy