"Забързване" на компилатора

Привет, колеги!

 

Вчера пробвах няколко варианта за компилиране, като целта ми беше да видя на практика ефекта им върху времето за компилация. Получиха се интересни резултати и затова реших да ги споделя и тук.

 

За тест използвах проекта от курса, а това са времената, които засякох на машината ми (i7, 6-cores + HT, Ubuntu 20.04), използвайки time командата, напр.:

$ time(cmake .. && make)

 

Command Time, s

cmake .. && make

17.151

rm -rf * && cmake .. && make

1.099 [rebuild from ccache]

cmake -DFAST=1 .. && make

7.243

cmake .. && make -j12

5.967

cmake -DFAST=1 .. && make -j12

5.815

cmake .. && cmake --build . -j12

5.742

cmake -DFAST=1 .. && cmake --build . -j12

5.870

cmake -G"Ninja" .. && ninja -j 12

4.220

cmake -DFAST=1 -G"Ninja" .. && ninja -j 12           

2.619

 

Забележки:

  1. -DFAST=1 активира CCache и Unity Build в CMakeList.txt (някъде в началото му):  
    if(FAST) # cmake .. -DFAST=1
        message(STATUS "Unity and CCache enabled")
        set(CMAKE_CXX_COMPILER_LAUNCHER ccache)
        set(CMAKE_UNITY_BUILD true)
    endif(FAST)

     

  2. -G"Ninja" сменя билд системата от "Unix Makefiles" на Ninja - "Ninja ... Its distinguishing goal is to be fast.". За да се използва, трябва предварително да се инсталирара на системата: sudo apt install ninja-build, като билдването става с командата ninja (вместо с make или cmake --build .), а като доп. параметър може да се зададе и в колко треда да рънва (напр. -j 12)

  3. CCache - "a fast C/C++ compiler cache.". Прави точно това - кешира резултата от последната компилация на даден файл и спестява прекомпилирането му. Това работи дори и ако изтрием всички файловe от build папката, както е видно от теста на втори ред. Инсталира се допълнително на системата с: sudo apt install ccache. Ако по някаква причина искаме ръчно да зачистим кеша (например между отделните тестове), може да го направим с командата "ccache -C" (с главна буква C). 

  4. UNITY_BUILD: "... target source files will be combined into batches for faster compilation. This is done by creating a (set of) unity sources which #include the original sources, then compiling these unity sources instead of the originals.". По този начин се спестява инклудването и прекомпилирането на повтарящи се хедъри и се облекчава линкването. Използването му може да доведе и до някои проблеми - ето една добра статия по темата от Виктор Кирилов (той има и няколко talk-a в yuotube на същата тема). Аз не се натъкнах на проблеми, но и проектът не е кой-знае колко голям.

  5. За всички паралени компилации съм използвал 12 треда за да избегна дефолтните стойности при различните билд системи.

  6. Между отделните тестове съм зачиствал съдържанието на build папката (rm -rf *) и ccache-a (ccache -C)

 

Коментари по резултатите:

  1. Използването на UNITY_BUILD за тестовия проект подобри времето за компилация само в два случая: компилиране в един тред (17s -> 7s) и при билдване с Ninja (4.2 --> 2.6s)

  2. make и cmake --build . са идентични като скорост както с един, така и с няколко треда и не се влияят от UNITY_BUILD

  3. CCache смъква времената за компилция значително, но се опасявам, че ползите от него не са универсални, а са в ограничени сценарии - без промени по файловете, затриване на build папката (защото и make/cmake/ninja не прекомпилират непроменените юнити) или използване на един модул в множество проекти (в този случй ще се използва кеша от билда за друг проект). От друга страна, не забелязах да пречи (освен да пълни диска, може би).

  4. Ninja отвява конкуренцията, като дори и без UNITY_BUILD е с около 30% по-бърза от make/cmake (5.8 -> 4.2s), a с UNITY_BUILD е над 50% по-бърза (т.е. отнема наполовина по-малко време: 5.8 -> 2.6s). Не съм забелязал никакви проблеми при използването ѝ до момента.