Skip to content

Conversation

maflcko
Copy link
Member

@maflcko maflcko commented Apr 25, 2022

This gets rid of the value*1000 manual conversion.

@DrahtBot
Copy link
Contributor

DrahtBot commented Apr 25, 2022

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Conflicts

Reviewers, this pull request conflicts with the following ones:

  • #25619 (net: avoid overriding non-virtual ToString() in CService and use better naming by vasild)
  • #25203 (logging: update to severity-based logging by jonatack)

If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

@naumenkogs
Copy link
Member

ACK fae94c6

@maflcko
Copy link
Member Author

maflcko commented Apr 29, 2022

@ajtowns You might be interested in (N)ACKing this change, based on the conversation in #24697 (comment)

@maflcko maflcko force-pushed the 2204-feeler-type- branch 2 times, most recently from fa7ca1e to fa9970a Compare April 30, 2022 08:37
@fanquake fanquake requested review from ajtowns and naumenkogs May 6, 2022 08:35
Copy link
Contributor

@w0xlt w0xlt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review ACK fa9970a

Copy link
Contributor

@w0xlt w0xlt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reACK fac6af7

{
using Dur = typename Chrono::duration;
return range.count() > 0 ? /* interval [0..range) */ Dur{randrange(range.count())} :
range.count() < 0 ? /* interval (range..0] */ -Dur{randrange(-range.count())} :
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why support negative ranges?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some call sites may use a negative range. For example in addr relay, the timestamp of some address messages is randomly pushed into the past.

Also, it seems safer when the alternative is either unspecified behaviour, or a crash.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The behavior here still seems odd in those cases. I'd expect call sites that actually can result in negative range values to want "rand_uniform_duration(T)" to mean: "give me a uniform duration not exceeding T". If T is negative, that probably means just returning 0?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, the interval is determined at run-time and the passed in value can either mean the start or the end of the interval, with the other value being 0.

I am not sure if mapping any negative value to a constant 0 is less confusing. And I couldn't find another solution that is well defined at run time (no unspecified behaviour, no crash).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I'm not objecting to this change. It just strikes me as bizarre semantics; the simplest interpretation of a range is specifying how wide the window of possible values is - and that simply cannot be negative.

An alternative is always returning range itself if it is <= 0. That at least satisfies the constraint "never return a value exceeding range", and probably works just as well for the intended call sites (who I suspect use to determine how long to wait)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there is a minimal, theoretical advantage to disallowing negative values, as the inverting the most negative value is an integer sanitizer violation. Though, this shouldn't affect execution of a program that is not compiled with the integer sanitizer and shouldn't happen in practise either.

What is the "C++20" syntax, if I may ask?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With C++20 you can pass a duration to a template, and then do a static_assert on its value, so you'd write rand_uniform_duration<dur>() instead of rand_uniform_duration(dur) and get the compile-time check.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, with dur you mean static_duration, not std::chrono::duration?

I can't get it to work with std::chrono::duration:

#include <chrono>

using namespace std::chrono_literals;

struct FRC {
    template <std::chrono::duration range>
    auto rand_uniform_delay(auto time) {
        return time + rand_uniform_duration<decltype(time)::duration, range>();
    }
    template <typename Duration, std::chrono::duration range>
    Duration rand_uniform_duration() noexcept {
        static_assert(range.count() > 0);
        return Duration{randrange(range.count())};
    }
};

int main() {
    FRC frc;
    frc.rand_uniform_delay<9h>(std::chrono::sys_seconds{1s});
    frc.rand_uniform_duration<std::chrono::seconds, 9h>();
}

https://godbolt.org/z/8Y868s98K

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I'm not really sure why it doesn't work (well, std::chrono::duration needs template parameters and stuff, but even after fixing that it doesn't work)

Here's something that does, via a wrapper class. Not sure that's any better than @theuni's c++17 compatible wrapper. https://godbolt.org/z/nnKx4fde5

#include <chrono>

int64_t randrange(int64_t x) { return x / 2; }

using namespace std::chrono_literals;

template<typename dur=std::chrono::seconds>
struct template_duration
{
    const int64_t count;
    using duration = dur;
    constexpr template_duration(dur f) : count{f.count()} { }
    constexpr dur to_dur() const { return dur{count}; }
};
template<typename dur>
constexpr template_duration<dur> tmpl_dur(const dur& d) { return {d}; }

struct FRC {
    template <typename Duration, auto range>
    Duration rand_uniform_duration() noexcept {
        static_assert(range.count > 0);
        return Duration{randrange(Duration{range.to_dur()}.count())};
    }

    template <auto range, typename X>
    X rand_uniform_delay(X time) noexcept {
        return time + rand_uniform_duration<typename X::duration, range>();
    }    
};

int main() {
    FRC frc;
    constexpr auto DELAY_HOURS{tmpl_dur(8h)};
    auto now = std::chrono::sys_seconds{1s};
    frc.rand_uniform_duration<std::chrono::seconds, DELAY_HOURS>();
    frc.rand_uniform_delay<DELAY_HOURS>(now);
}

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Happy to use different std-lib syntax, but anything that requires a wrapper class that re-implements stuff seems overkill to solve a problem that doesn't exist.

@@ -19,13 +19,12 @@
class CThreadInterrupt
{
public:
using Clock = std::chrono::steady_clock;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maflcko
Copy link
Member Author

maflcko commented May 27, 2022

Rebased only for now

MacroFake added 2 commits July 13, 2022 15:20
Overloading sleep_for is not needed, as

* seconds and minutes can be converted to milliseconds by the compiler,
  not needing a duration_cast
* std::condition_variable::wait_for will convert milliseconds to the
  duration type of the underlying clock

So simply expose the clock.
@maflcko
Copy link
Member Author

maflcko commented Jul 13, 2022

Rebased

@naumenkogs
Copy link
Member

utACK fa74e72

@fanquake fanquake requested review from dergoegge and mzumsande July 26, 2022 11:59
@dergoegge
Copy link
Member

Code review ACK fa74e72

@fanquake fanquake merged commit 5671217 into bitcoin:master Jul 26, 2022
@maflcko maflcko deleted the 2204-feeler-type-🐴 branch July 26, 2022 15:51
sidhujag pushed a commit to syscoin/syscoin that referenced this pull request Jul 27, 2022
…d::chrono)

fa74e72 refactor: Make FEELER_SLEEP_WINDOW type safe (std::chrono) (MacroFake)
fa3b3cb Expose underlying clock in CThreadInterrupt (MacroFake)

Pull request description:

  This gets rid of the `value*1000` manual conversion.

ACKs for top commit:
  naumenkogs:
    utACK fa74e72
  dergoegge:
    Code review ACK fa74e72

Tree-SHA512: 90409c05c25f0dd2f1c4dead78f707ebfd78b7d84ea4db9fcefd9c4958a1a3338ac657cd9e99eb8b47d52d4485fa3c947dce4ee1559fb56ae65878685e1ed9a3
@bitcoin bitcoin locked and limited conversation to collaborators Jul 26, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants