threading: use std::chrono for timestamps #9566

pull theuni wants to merge 2 commits into bitcoin:master from theuni:nuke-boost-chrono2 changing 5 files +130 −17
  1. theuni commented at 10:58 pm on January 16, 2017: member

    Obviously not for 0.14.

    Though boost’s chrono hides the racy gmtime() issue nicely, it’s really just using gmtime_r internally. This switches to the same thing, but without the boost indirection.

    PRing this separately from other boost removals because it’s not a 1:1 replacement.

  2. fanquake added the label Refactoring on Jan 16, 2017
  3. fanquake commented at 2:28 am on January 17, 2017: member

    Failed on both Windows builds with:

    0utiltime.cpp: In function const tm gmtime_int(time_t):
    1utiltime.cpp:31:25: error: cannot convert time_t* {aka long int*} to tm* for argument 1 to errno_t gmtime_s(tm*, const time_t*)
    2     gmtime_s(&time, &out);
    
  4. time: Use std::chrono for time rather than boost
    Unfortunately, there's still no standard way of printing the current time in a
    threadsafe way. Digging down into boost's approach, they simply use gmtime_r
    when possible, as guessed by availability macros.
    
    We now use the same approach, but use autotools to detect whether gmtime_r or
    gmtime_s can be used, or as a fallback, the racy gmtime.
    
    Note that MilliSleep was not replaced because it is an interruption point. That
    can be done once boost threads are all gone.
    0512b02750
  5. time: add runtime sanity check
    std::chrono::system_clock.time_since_epoch and time_t(0) are not guaranteed
    to use the Unix epoch timestamp, but in practice they almost certainly will.
    Any differing behavior will be assumed to be an error, unless certain
    platforms prove to consistently deviate, at which point we'll cope with it
    by adding offsets.
    
    Do a quick runtime check to verify that
    time_t(0) == std::chrono::system_clock's epoch time == unix epoch.
    9bd32ce6aa
  6. theuni force-pushed on Jan 17, 2017
  7. theuni commented at 3:58 am on January 17, 2017: member

    Of course windows has reversed arguments. Why wouldn’t it?

    Pushed the reversal.

  8. in src/utiltime.cpp: in 9bd32ce6aa
    38+    out = *gmtime(&time);
    39+#endif
    40+    return out;
    41+}
    42+
    43+bool ChronoSanityCheck()
    


    laanwj commented at 6:28 am on January 17, 2017:

    Needing something like this makes me wonder if we’re not better off just using the C time functions, which guarantee being based on the UNIX epoch.

    Especially as we’re already probing for gmtime_int anyway. This seems double.

    Do we need something that is only offered by std::chrono? (or needs much less code with std::chrono)


    theuni commented at 4:50 pm on January 17, 2017:

    @laanwj Best I can tell from google and reading the c spec, it’s not guaranteed to be based on the UNIX epoch either :(. Of course, I’ve never seen an implementation that isn’t, as that would likely break years worth of assumptions. And based on that, I would assume that c++ implementations will be using the underlying c implementation.

    So my logic was: if we can run a quick sanity check here to be sure that c/c++/unix epoch are all aligned, then we can use c apis and std::chrono interchangeably throughout the codebase without worry.

    As for why chrono here, it was to avoid gettimeofday portability issues. If you’d prefer to work around those instead, no problem.

    You’re right though that DateTimeStrFormat is kinda clunky. I only used c++ there to avoid c string size guessing. I’m also happy to switch that if you’d prefer.


    laanwj commented at 8:35 pm on January 17, 2017:

    Best I can tell from google and reading the c spec, it’s not guaranteed to be based on the UNIX epoch either :(

    Which ones? The man page of “gmtime” tells me the following:

    0       The  ctime(),  gmtime()  and localtime() functions all take an argument of data type time_t, which represents calendar time.  When interpreted as an absolute time value, it represents the
    1       number of seconds elapsed since the Epoch, 1970-01-01 00:00:00 +0000 (UTC).
    

    Same for gettimeofday:

    0       and gives the number of seconds and microseconds since the Epoch (see time(2)).  The tz argument is a struct timezone:
    

    If using std::chrono makes anything less hassle I’m fine with using it. It just seems like a lot of code necessary to work around issues (and that’s just to get started using it!), but you’re right that gettimeofday and strftime have their own issues.


    theuni commented at 9:10 pm on January 17, 2017:

    @laanwj Posix uses a value since the Unix epoch, but time_t is implementation-defined according to the c spec. But it really doesn’t matter, realistically it’ll be the Unix epoch everywhere we run. Sorry for the distraction.

    I only brought it up because the c++ system_clock’s epoch is technically implementation-defined as well, I was just making the case that it’s probably just as safe to assume as with c.

  9. zstardust commented at 2:44 pm on January 17, 2017: none
    There’s a few places in Bitcoin Core where non monotonic time stamps can cause the node to act strangely, for example if NTP tweaks the time backwards between a p2p PING and PONG, the int64 for node latency can overflow. Without much review, does this change any of the behavior in that respect? chrono::steady_clock assures monotone time where required.
  10. theuni commented at 4:53 pm on January 17, 2017: member
    @zstardust There is (should be) no behavioral change here. steady_clock would indeed make sense for some of those cases.
  11. laanwj commented at 8:31 pm on January 17, 2017: member
    Agreed, using monotonic clock makes sense where only differences in time are important, when there is no need to print the time (as it will have an arbitrary starting offset). That’s orthogonal to the changes here, though.
  12. fanquake added this to the milestone 0.15.0 on Jan 18, 2017
  13. TheBlueMatt commented at 4:43 pm on January 23, 2017: member
    I think we need to think more about how we use time everywhere, see eg the issues turned up in #9606 - do we want our own types for time to enforce that we dont compare mock and non-mock time? Do we want multiple types of mock times? etc.
  14. theuni commented at 6:22 pm on January 23, 2017: member

    @TheBlueMatt This is intended to just be a replacement of what we have now. The behavioral changes can come next.

    I have an impl of a clock/time_point that I’ve made that is explicitly non-convertable from one type to another. Happy to PR that for discussion as well. I expect that it would replace our current timestamp usage, but I figured it’d be best to get rid of boost first, since the boost condvars use boost::chrono.

  15. jtimon commented at 1:48 am on February 1, 2017: contributor
    Concept ACK. With C++ std or with C time functions. Seems like removing boost’s dependency here is better irrespective of next steps. Needs rebase.
  16. in src/utiltime.cpp: in 9bd32ce6aa
    60+    if (nTime != zeroTime)
    61+        return false;
    62+
    63+    // Check that the above zero time is actually equal to the known unix timestamp.
    64+    tm epoch = gmtime_int(nTime);
    65+    if ((epoch.tm_sec != 0)  || \
    


    laanwj commented at 7:56 am on February 1, 2017:
    Why the \ at the end of the line?
  17. in src/utiltime.cpp: in 9bd32ce6aa
    51+    // Create a new clock from time_t(0) and make sure that it represents 0
    52+    // seconds from the system_clock's time_since_epoch. Then convert that back
    53+    // to a time_t and verify that it's the same as before.
    54+    const time_t zeroTime{};
    55+    auto clock = std::chrono::system_clock::from_time_t(zeroTime);
    56+    if (std::chrono::duration_cast<std::chrono::seconds>(clock.time_since_epoch()).count() != 0)
    


    laanwj commented at 7:57 am on February 1, 2017:
    nit: bracing style: we decided to always use braces unless the if and the statement can be on one line: https://github.com/bitcoin/bitcoin/blob/master/doc/developer-notes.md
  18. laanwj commented at 9:05 am on March 9, 2017: member
    Needs rebase/nit fix.
  19. laanwj commented at 8:27 am on April 19, 2017: member
    Is this still in your plans @theuni?
  20. laanwj assigned theuni on Jun 26, 2017
  21. theuni commented at 8:10 pm on June 27, 2017: member
    Thanks for the reminder, I’ll circle back to this.
  22. sipa commented at 6:10 pm on July 13, 2017: member
    What is the status here? Going to make it for 0.15?
  23. theuni commented at 7:00 pm on July 13, 2017: member
    I’ll go ahead and rebase/clean this up now, but it’s not a priority for 0.15.
  24. laanwj added this to the milestone 0.16.0 on Jul 13, 2017
  25. laanwj removed this from the milestone 0.15.0 on Jul 13, 2017
  26. danra commented at 3:34 pm on September 30, 2017: contributor
    Needs rebase
  27. MarcoFalke removed this from the milestone 0.16.0 on Nov 22, 2017
  28. MarcoFalke added this to the milestone 0.17.0 on Nov 22, 2017
  29. laanwj commented at 6:32 pm on February 8, 2018: member
    @theuni Ping
  30. theuni commented at 7:44 pm on March 6, 2018: member
    After discussion with @laanwj, closing this in favor of a different approach.
  31. theuni closed this on Mar 6, 2018

  32. fanquake moved this from the "In progress" to the "Later" column in a project

  33. MarcoFalke commented at 8:01 pm on December 3, 2018: member
    Anyone remembers what the “different approach” was?
  34. MarcoFalke commented at 9:43 pm on March 6, 2020: member
    ping @theuni :grimacing:
  35. MarcoFalke commented at 3:09 pm on March 7, 2020: member

    After discussion with @laanwj, closing this in favor of a different approach.

    Or maybe, ping @laanwj :grimacing:

  36. DrahtBot locked this on Feb 15, 2022

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2024-10-04 22:12 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me