Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to improve compilation speed? #836

Closed
evandrocoan opened this issue Feb 28, 2017 · 6 comments
Closed

How to improve compilation speed? #836

evandrocoan opened this issue Feb 28, 2017 · 6 comments

Comments

@evandrocoan
Copy link

evandrocoan commented Feb 28, 2017

How to improve compilation speed?

First, there is not any mention of the CATCH_CONFIG_FAST_COMPILE on the single include file single_include\catch.hpp. How it is supposed to improve the compilation time?


On my computer, takes about 3.2 seconds to build and run a simple application on my computer using g++ 5.4-cygwin . Seems acceptable time, as my CPU is under-clocked 67%.

However, following the steps on https://github.com/philsquared/Catch/blob/master/docs/slow-compiles.md, takes about 21.3 seconds to build & run this simple unit test, instead of 40 seconds when I was building the main altogether:

catch_tests.cpp

#include "libraries/Catch/include/catch.hpp"

unsigned int Factorial( unsigned int number )
{
    return number <= 1 ? number : Factorial(number-1)*number;
}

TEST_CASE( "Factorials are computed", "[factorial]" )
{
    REQUIRE( Factorial(1) == 1 );
    REQUIRE( Factorial(2) == 2 );
    REQUIRE( Factorial(3) == 6 );
    REQUIRE( Factorial(10) == 3628800 );
}

Now I am including CATCH_CONFIG_FAST_COMPILE on both files, in hope to improve this speed:

catch_main.cpp

#define CATCH_CONFIG_MAIN
#define CATCH_CONFIG_FAST_COMPILE
#include "libraries/Catch/include/catch.hpp"

catch_tests.cpp

#define CATCH_CONFIG_FAST_COMPILE
#include "libraries/Catch/include/catch.hpp"

unsigned int Factorial( unsigned int number )
{
    return number <= 1 ? number : Factorial(number-1)*number;
}

TEST_CASE( "Factorials are computed", "[factorial]" )
{
    REQUIRE( Factorial(1) == 1 );
    REQUIRE( Factorial(2) == 2 );
    REQUIRE( Factorial(3) == 6 );
    REQUIRE( Factorial(10) == 3628800 );
}

But it does not seem to improve the compilation speed. Are there anything it could be done beyond not use Catch as Unit Test framework, to improve the compilation speed from 21.3 seconds?


I am using this makefile to build:

Makefile

PROGRAM_BINARY              = main.exe
PROGRAM_MAIN_FILE_NAME      = main.cpp
PROGRAM_MAIN_FOLDER_INCLUDE = .

DRIVER_CLASS_TESTS_FILE  = unit_tests/catch_tests
DRIVER_CLASS_SOURCE_NAME = unit_tests/catch_main


main.exe: $(PROGRAM_MAIN_FILE_NAME)
	g++ --std=c++11 $(PROGRAM_MAIN_FILE_NAME) -I $(PROGRAM_MAIN_FOLDER_INCLUDE) -o main


catch_tests: $(DRIVER_CLASS_SOURCE_NAME).o
	g++ --std=c++11 $(DRIVER_CLASS_SOURCE_NAME).o $(DRIVER_CLASS_TESTS_FILE).cpp -I $(PROGRAM_MAIN_FOLDER_INCLUDE) -o main

$(DRIVER_CLASS_SOURCE_NAME).o: $(DRIVER_CLASS_SOURCE_NAME).cpp
	g++ $(DRIVER_CLASS_SOURCE_NAME).cpp -I $(PROGRAM_MAIN_FOLDER_INCLUDE) -c -o $(DRIVER_CLASS_SOURCE_NAME).o


clean:
	$(RM) $(DRIVER_CLASS_SOURCE_NAME).o
	$(RM) $(PROGRAM_BINARY)
@philsquared
Copy link
Collaborator

Hi @evandrocoan,

Thanks for the detailed report. However I do wonder if you have the latest version of Catch (1.8.0)? There are definitely #if defined(CATCH_CONFIG_FAST_COMPILE) lines at lines 2131 and 8909 in the single_include. Note that this was only released yesterday but the changes to the docs went in early.

The compile time improvements should be noticeable - but not earth shattering. This is just an incremental step - and a place for us to put slightly more disruptive changes in (hence the need to opt-in with the #define).

As for why having the separate main file actually takes longer than without: that's because you're building the whole project - which now has the same amount of user code, but more translation units. The advice given in "slow-compiles" is really to improve incremental compile times - which is where you usually most feel the pain if compilation is slow. When you are in a test-compile-check cycle you don't usually need to rebuild the main source file, so having that contain the more heavyweight portion of Catch is a win.

@philsquared philsquared added the Resolved - pending review Issue waiting for feedback from the original author label Mar 1, 2017
@evandrocoan
Copy link
Author

Yeah, now I updated and I found them also.

I was not using the include file single_include, but directly the catch.hpp. My single_include was the version v1.7.2. Now I updated and I am using directly the single_include.

The compile time still do not improving. Sometimes I got 41~38s overrall, and 21~19 only the tests file. These are the files I am using now:

catch_main.cpp

#define CATCH_CONFIG_MAIN
#define CATCH_CONFIG_FAST_COMPILE
#include "libraries/Catch/single_include/catch.hpp"

catch_tests.cpp

#define CATCH_CONFIG_FAST_COMPILE
#include "libraries/Catch/single_include/catch.hpp"


unsigned int Factorial( unsigned int number )
{
    return number <= 1 ? number : Factorial(number-1)*number;
}

TEST_CASE( "Factorials are computed", "[factorial]" )
{
    REQUIRE( Factorial(1) == 1 );
    REQUIRE( Factorial(2) == 2 );
    REQUIRE( Factorial(3) == 6 );
    REQUIRE( Factorial(10) == 3628800 );
}

Basically 99% of the time the ld.exe is running:

2

@horenmar
Copy link
Member

horenmar commented Mar 8, 2017

So, I got around looking at this and I have to ask: Was your g++ binary compiled in debug mode? Or maybe the linker, because the attached gif shows ld taking long time.

Even my pretty ancient Zacate (1600 MHz, tiny caches, generally quite slow), can compile Catch main in 15s. My actual notebook takes ~8s to compile the main, ~9s to compile the factorial example + main.

As to the new compile time option, CATCH_CONFIG_FAST_COMPILE, it helps only when compiling test files. Under Linux it can speed up the compilation by ~10%, so it can be quite helpful if you have many tests, but makes basically no difference when compiling main is the dominant time cost.

@refi64
Copy link

refi64 commented Mar 8, 2017

Also, you could try out Zapcc, which is free for (quot from their page) non-commercial entities, and for start-up companies in pre revenues/funding stages.

@evandrocoan
Copy link
Author

evandrocoan commented Mar 8, 2017

@horenmar my gcc is 5.4.0@cygwin, also I am not setting any special options for the linker, neither the g++ as -g. The command line I am using the exactly the one on the make file I am posting above. More precisely, that is the exactly Makefile I am using to build.

Though, your compilation times ~8s and ~9s are pretty close to mine 21s and 19s. My processor is an i3-390m @2.67GHz, underclocked 67% leading to ~@1.0GHz per core.

@kirbyfan64 thanks for pointing Zapcc, is could be useful some day I need more speed. For now I replaced Catch by doctest. Now with doctest the same compilation takes ~8s the main file, and ~2.8s a simple factorial test file, which is pretty good, as I only need to compile the main file, mostly one life time. Actually, the simple factorial test at ~2.8s with doctest is compiling faster than my own simple application which takes about ~3.2s.

@horenmar
Copy link
Member

@evandrocoan In general, Catch's main takes a looong time to compile and the tests aren't exactly fast either, so if you are stuck with 1GHz cores, then you will see some crazy compile times.

If doctest covers your need, use it, it was made as reimplementation of Catch's core with minimal compile time overhead, but is missing quite a few features. We aren't out for world domination and will not hunt you down for not using Catch 😄

@horenmar horenmar removed the Resolved - pending review Issue waiting for feedback from the original author label Mar 13, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants