Archive for the ‘gcc’ 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.

glibc-2.7 makecontext issues on x86_64

Monday, December 28th, 2009

Looks like passing 64 bit values(e.g pointers) into makecontext is not working properly on x86_64. We are using makecontext for coroutines implementation and its proper working is vital for us.

I’ve been struggling with this bug for a couple of days and have finally found a solution for it. Actually the solution is trivial it was the actual process of spotting this bug which took so much time. By the way, this issue was resolved in the latest releases of glibc, so nothing to worry about if you are using gcc older than 4.2.4.

Ok, here is the solution - pass your 64 bit pointer as two ints :) Here it comes:

#include <stdlib.h>
#include <ucontext.h>
 
struct Foo{};
 
#if defined(__GNUC__) && defined(__x86_64__) && __GNUC__ < 5 && __GNUC_MINOR__ < 3
void thread(__uint32_t p1, __uint32_t p2)
{
  Foo* foo = (Foo*)((__uint64_t)p2 | ((__uint64_t)p1) << 32);
#else
void thread(Foo* foo)
{
#endif
  ...
}
 
#define FIBER_STACK 1024*64
 
ucontext_t child
 
int main()
{
  getcontext (&child);
 
  // Modify the context to a new stack
  child.uc_link = 0;
  child.uc_stack.ss_sp = malloc (FIBER_STACK);
  child.uc_stack.ss_size = FIBER_STACK;
  child.uc_stack.ss_flags = 0;
 
   Foo foo;
 
#if defined(__GNUC__) && defined(__x86_64__) && __GNUC__ < 5 && __GNUC_MINOR__ < 3
  __uint32_t p1,p2;
  p1 = (__uint32_t)((0x00000000FFFFFFFF) & ((__uint64_t)&foo) >> 32);
  p2 = (__uint32_t)(0x00000000FFFFFFFF & (__uint64_t)&foo);
 
  makecontext (&child, (void (*)())&thread, 2, p1, p2);
#else
  makecontext (&child, (void (*)())&thread, 1, &foo);
#endif
}