time differences with std::chrono::system_clock / std::chrono::high_resolution_clock
Asked Answered
S

3

12

Consider the following piece of code

#include <chrono>
#include <iostream>
#include <thread>

int main()
{
   using std::chrono::system_clock;
   using std::chrono::milliseconds;
   using std::chrono::nanoseconds;
   using std::chrono::duration_cast;
   const auto duration = milliseconds(100);
   const auto start = system_clock::now();
   std::this_thread::sleep_for(duration);
   const auto stop = system_clock::now();
   const auto d_correct = duration_cast<nanoseconds>(duration).count();
   const auto d_actual = duration_cast<nanoseconds>(stop - start).count();
   std::cout << "Difference is " << d_actual << ", and it should be roughly " << d_correct << "\n";
}

What we expect is something on the line of

Difference is 100039989, and it should be roughly 100000000

See this demo where it works absolutely fine.

However, on my machine, there are several compilers installed which seem to cause a malconfiguration according to this answer here on Stack Overflow.

Hence I tried the suggested fix: Setting the correct LD_LIBRARY_PATH. These are the combinations with output I tried (among others with 4.4 and 4.6...)

g++-4.7 time.cpp -pthread -std=c++11; LD_LIBRARY_PATH=/usr/lib/gcc/i686-linux-gnu/4.7/ ./a.out

Difference is 100126, and it should be roughly 100000000

g++-4.7 time.cpp -pthread -std=c++11; LD_LIBRARY_PATH=/usr/lib/gcc/i686-linux-gnu/4.8/ ./a.out

Difference is 100132, and it should be roughly 100000000

g++-4.8 time.cpp -pthread -std=c++11; LD_LIBRARY_PATH=/usr/lib/gcc/i686-linux-gnu/4.7/ ./a.out

Difference is 100085953, and it should be roughly 100000000

g++-4.8 time.cpp -pthread -std=c++11; LD_LIBRARY_PATH=/usr/lib/gcc/i686-linux-gnu/4.8/ ./a.out

Difference is 100156418, and it should be roughly 100000000

It seems that no matter how, compiling with g++-4.8 works fine using any of the libstdc++, while compiling with g++-4.7 results in a broken situation.

Am I doing anything wrong here in the compiler / binary invocation or is it a bug in g++-4.7? (It's g++-4.7.3 and g++-4.8.1 to be specific)

For (the probably most ugly) workaround, I can of course measure for a tiny amount of time, compare it against the expected difference and come up with a factor. However I would very much like to solve this elegantly.

Swagerty answered 21/2, 2014 at 14:34 Comment(9)
If it helps, this page mentions that the C++11 clock ABI changed in GCC 4.8.1: gcc.gnu.org/gcc-4.8/changes.htmlEugenaeugene
@JohnZwinck This is probably related, but I don't see how I can fix the situation with 4.7 (I want at least two compiler versions for the product I'm working on.. At work, only my dev machine has 4.8, all others run <= 4.7)Swagerty
GCC 4.7 doesn't have 100% working support for C++11, so you may be out of luck there, or at least need some nasty workarounds. I'm not really sure, and wasn't able to dig up a more specific problem report from the GCC site.Eugenaeugene
@JohnZwinck Well this is an optional feature I'm working on, so if this is unfixable with 4.7, it's out. But it's such a shiny feature (of course not the demo code here ;-) )Swagerty
How is there any viable conclusion besides that they fixed a bug after the 4.7 release? If 4.7 ever worked, then you have an incompatibility between the installed stdlib binaries and headers. But that would be an exceptional instance of misconfiguration.Deirdre
@Deirdre Well apparently, this issue doesn't exist on my machine only, see the linked Q/A. However, the fix proposed there doesn't work for me. So we see that on most machines, 4.7 does work, but on some, it doesn't. I can only repeat myself and say that I would prefer to have at least two compiler versions compatible with my program..Swagerty
@Swagerty It might depend on OS or Linux distro, or the point release of GCC. You reproduced one symptom, but not being able to reproduce Wakely's fix proves that you aren't experiencing whatever he was describing.Deirdre
@Deirdre Obviously, that's why I'm asking for a fix. But it's almost certainly related. The difference in order of magnitude is to similar than to be just coincidence. Anyway, I simply installed some gcc versions on my Ubuntu system with the standard apt-get stuff. So there is a bug somewhere & I want to know where.Swagerty
@Swagerty Did you check to see if the start and stop times are "correct" and the difference is wrong, or if the times themselves are wrong (this might tell us if for example operator- is broken).Madlynmadman
S
8

I can't comment, but it seems to be a problem with the duration_cast only... I bumped your sleep up to 1000 ms, and ran it against the time utility. Indeed, it does sleep for 1 second.

#include <chrono>
#include <iostream>
#include <thread>

int main()
{
   using std::chrono::system_clock;
   using std::chrono::milliseconds;
   using std::chrono::nanoseconds;
   using std::chrono::duration_cast;
   const auto duration = milliseconds(1000);
   const auto start = system_clock::now();
   std::this_thread::sleep_for(duration);
   const auto stop = system_clock::now();
   const auto d_correct = duration_cast<nanoseconds>(duration).count();
   const auto d_actual = duration_cast<nanoseconds>(stop - start).count();
   std::cout << "Difference is " << d_actual << ", and it should be roughly " << d_correct << "\n";
}

Run it with the time utility:

g++-4.7 time.cpp -pthread -std=c++11; time LD_LIBRARY_PATH=/usr/lib/gcc/i686-linux-gnu/4.7/ ./a.out
Difference is 1000193, and it should be roughly 1000000000

real    0m1.004s
user    0m0.000s
sys     0m0.000s

So, indeed, it sure looks like a problem with the ABI. And my system is just as silly about using the newer version of libstdc++ as your system. We can confirm this with ldd and/or LD_DEBUG=files:

ldd a.out 
    linux-vdso.so.1 =>  (0x00007fff139fe000)
    libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007ff0595b7000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007ff0593a1000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007ff059183000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff058dba000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007ff058ab5000)
    /lib64/ld-linux-x86-64.so.2 (0x00007ff0598e6000)

SMOKING GUN! This definitely isn't the right libstdc++... And nothing I did could stop it!

My next experiment was to try linking with static libstdc++ (http://www.trilithium.com/johan/2005/06/static-libstdc/):

ln -s `g++-4.7 -print-file-name=libstdc++.a`
g++-4.7 -static-libgcc -L. time.cpp -pthread -std=c++11; time ./a.out
Difference is 1000141417, and it should be roughly 1000000000

real    0m1.003s
user    0m0.004s
sys     0m0.000s

ALL BETTER! So, overall, you're safe. There's nothing inherently wrong with GCC 4.7 (heh...), but what a nasty issue!

Seafaring answered 28/6, 2014 at 3:32 Comment(3)
Finally a sane answer! Thank you :)Swagerty
D'aw, shucks! My first one too!Seafaring
I know and I must say: it's really rare to encounter a good first answer. Please stay on this site :)Swagerty
A
0

try explicitly use duration_cast(system_time::now() - start).count()

Ark answered 5/3, 2014 at 7:44 Comment(3)
I guess I should have been more precise in my question. I edited to show that duration_cast does not solve the problem.Swagerty
maybe something is wrong in your g++4.7's header? if library header defines nanoseconds incorrectly, it will cause this problem. try a different version of g++4.7 or you can simply look into header files.Ark
The definition of nanoseconds depends on nano in ratio and is the same for all versions I have (4.4, 4.6, 4.7 and 4.8)Swagerty
P
0

A lot of times it is unavoidable to differentiate code according to the compiler version. I would suggest not solving the differentiation between 4.7 and 4.8 during run-time (the 'ugly' solution you mentioned). Do it in compile time instead.

#if __GNUC__ == 4 && __GNUC_MINOR__ > 7
   // your gcc 4.8 and above code here
#else
   // your gcc 4.7.x and below code here
#endif
Priapus answered 27/5, 2014 at 14:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.