Archive for the ‘c++’ Category

gcc precompiled headers weird behaviour with -c option

Sunday, March 28th, 2010

Short story

Use -fpch-preprocess option alongside with -c option in order to make precompiled headers work properly.

Update: I asked the same question on the gcc help mailing list and Ian Lance Taylor explained this strange behavior by my usage of distcc/ccache. These tools first preprocess the source that’s why this options is required.

Long story

I’m using gcc-4.4.1 on Linux and before trying precompiled headers in a really large project I decided to test them on a simple program. They “kinda work” but I was not happy with results and I was sure there was something wrong about my setup.

First of all, I wrote the following program(main.cpp) to test if they worked at all:

    #include <boost/bind.hpp>
    #include <boost/function.hpp>
    #include <boost/type_traits.hpp>
 
    int main()
    {
      return 0;
    }

Then I created the precompiled headers file pre.h(in the same directory) as follows:

    #include <boost/bind.hpp>
    #include <boost/function.hpp>
    #include <boost/type_traits.hpp>

…and compiled it:

    $ g++ -I. pre.h

(pre.h.gch was created)

After that I measured compile time with and without precompiled headers:

with pch

    $ time g++ -I. -include pre.h main.cpp

    real	0m0.128s
    user	0m0.088s
    sys	 0m0.048s

without pch

    $ time g++ -I. main.cpp 

    real	0m0.838s
    user	0m0.784s
    sys	 0m0.056s

So far so good! **Almost 7 times faster, that’s impressive!** Then I tried something more realistic. Since all my sources are built with -c option I tried using it and for some reason I couldn’t make pch play nicely with it. Here is what I did…

I created the test module foo.cpp as follows:

    #include <boost/bind.hpp>
    #include <boost/function.hpp>
    #include <boost/type_traits.hpp>
 
    int whatever()
    {
      return 0;
    }

Here are the timings of my attempts to build the module foo.cpp with and without pch:

with pch

    $ time g++ -I. -include pre.h -c foo.cpp 

    real	0m0.357s
    user	0m0.348s
    sys	0m0.012s

without pch

    $ time g++ -I. -c foo.cpp 

    real	0m0.330s
    user	0m0.292s
    sys	0m0.044s

That was quite strange, looked like there was no speedup at all!(and, yes, I ran timings for several times). It turned out precompiled headers were not used at all in this case, I checked it with -H option(output of g++ -I. -include pre.h -c foo.cpp -H didn’t list pre.h.gch).

I was pretty much in despair looking at gcc’s man page and trying misc. options…until I stumbled upon -fpch-preprocess. Hell, why not try using it and it worked well all of a sudden :) Here is the timings:

$ time g++ -I. -include pre.h -c foo.cpp -fpch-preprocess

real	0m0.028s
user	0m0.016s
sys	0m0.016s

I pretty vaguely understand why it worked so you if you do, please explain it in comments, I’d be very grateful for that.

Using boost::threadpool with boost::future

Thursday, December 10th, 2009

Here is a small c++ function which allows you to submit async jobs into the thread pool and track their execution status using the conception of futures:

#include "boost/threadpool.hpp"
#include "boost/future.hpp"
#include "boost/utility/result_of.hpp"
#include "boost/shared_ptr.hpp"
 
template<typename Thp, typename Func>
boost::shared_future< typename boost::result_of<Func()>::type >
submit_job(Thp& thp, Func f)
{
  typedef typename boost::result_of<Func()>::type result;
  typedef boost::packaged_task<result> packaged_task;
  typedef boost::shared_ptr<boost::packaged_task<result> > packaged_task_ptr;
 
  packaged_task_ptr task(new packaged_task(f));
  boost::shared_future<result> res(task->get_future());
  boost::threadpool::schedule(thp, boost::bind(&packaged_task::operator(), task));
 
  return res;
}

Here is a small example of its possible usage:

User lookup_user_in_database(int id) { ... }
...
int main()
{
  boost::threadpool::pool thp(3);//number of threads
  boost::shared_future<User> future = 
    submit_job(boost::bind(lookup_user_in_database, 10));
  while(!future.is_ready())
  { 
  //do something useful
  }
  User = future.get();
  ...
}

boost::futures are now finally officially shipped with boost starting with 1.41 release. boost::threadpool is not yet an official boost library, however you can find it here.

Much kudos to authors of these amazing libraries!