-
Notifications
You must be signed in to change notification settings - Fork 3k
Use std::chrono based functions #13046
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@hugueskamba, thank you for your changes. |
1c342d7
to
035fd51
Compare
f567894
to
043268d
Compare
features/cellular/framework/targets/UBLOX/AT/UBLOX_AT_CellularNetwork.cpp
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Various comments - some of them apply to multiple changes.
This is very much a "bare minimum" Chrono "conversion". Silencing the warnings, but not really following through, and leaving absolutely all touched code using integers as much as possible.
There is a question of how far you can go, when you're potentially touching a lot of code, and maybe that code is not Mbed-specific, but this is clearly erring too far on the "don't touch anything, and cast at the last minute" side.
Certainly having a define for SOCKET_TIMEOUT
as (1 * 1000)
and then having C++ code using it as microseconds(SOCKET_TIMEOUT)
makes no sense. Define it as 1ms
in the first place.
(Namespace pollution limitations would force that to be std::chrono::milliseconds(1)
if in a header, but you can still not be an integer).
Start with the easy ones, then we can see if it's worth doing a fuller conversion on, say, the RfPhys.
To some extent the reason they were left is because I could see they needed a fuller converison, and just didn't get around to it. I've not left the "easy" ones :)
components/802.15.4_RF/atmel-rf-driver/source/NanostackRfPhyAT86RF215.cpp
Outdated
Show resolved
Hide resolved
@@ -189,7 +192,7 @@ static TestPins *test_pins; | |||
|
|||
static uint32_t rf_get_timestamp(void) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you're doing a Chrono conversion, it's usually better to make an effort to pass it through the codebase as much as you can. If all you do is convert at the last moment for the APIs, but keep all your own code using integers, then you're not really following through, or doing much to catch errors.
This code should be using HighResClock::time_point
s for its timestamps, and using HighResClock::now()
to get the time.
It's currently using a Timer
, but that's no longer the best tool. It doesn't want a stopwatch - it's not stopping and starting it - it wants a high-res monotonic clock. The only previous way to get that was a Timer
, but now there is HighResClock
. Just remember to do HighResClock::lock()
where the Timer::start()
currently is.
As it's currently engineered for 32-bit calculations, and seems to cope okay with them, you could maintain that by using a 32-bit version of
using microseconds_u32_t = std::chrono::duration<uint32_t, std::micro>;
using rf_timestamp_u32_t = std::chrono::time_point<HighResClock::time_point::clock, microseconds_u32_t>;
Then
static rf_timestamp_u32_t rf_get_timestamp(void)
{
return HighResClock::now();
}
if (tx_time != tx_time.min()) {
microseconds_u32_t backoff_time = tx_time - rf_get_timestamp();
// Max. time to TX can be 65ms, otherwise time has passed already -> send immediately
if (backoff_time <= 65ms) {
rf->cca_timer.attach(rf_csma_ca_timer_signal, backoff_time);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As this is a bit more involved. I have reverted the changes.
components/802.15.4_RF/atmel-rf-driver/source/NanostackRfPhyAtmel.cpp
Outdated
Show resolved
Hide resolved
mbed::callback(this, &GenericGap::on_advertising_timeout), | ||
durationCast<millisecond_t>(maxDuration).value() | ||
std::chrono::microseconds(durationCast<millisecond_t>(maxDuration).value()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hang on, this is a code-base with its own Chrono-like duration handling stuff. Either convert and replace that, or add some conversion operators. Absolutely no need to be doing this mess manually at usage sites. The usage site could look like:
_advertising_timeout.attach(
mbed::callback(this, &GenericGap::on_advertising_timeout),
maxDuration)
Adding user-defined conversion operators to Duration
seems simplest. I think this is it:
operator std::chrono::duration<Rep, std::ratio<TB, 1000000>::type>() const
{
return std::chrono::duration<Rep, std::ratio<TB, 1000000>::type>{duration};
}
I note that this original code is actually wrong, and the minimal Chrono conversion didn't spot it - it's passing milliseconds to microseconds, and you've faithfully reproduced the error. A correct Duration
->std::chrono::duration
conversion will clear it up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Durations are a strange things in BLE, we have many different units which are not based on ms and its multiple adding an interface where you can convert to and from was natural.
Replacing it with chrono
may help us in solving the problem. We just have to think of Ann efficient way of solving the boundary issue.
Thanks for spotting the issue, this is on the legacy compatibility path, we missed it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
New suggestion - a simple non-conversion-operator method:
auto Duration::valueChrono() const
{
return std::chrono::duration<Rep, typename std::ratio<TB, 1000000>::type>{duration};
}
@pan- I saw your suggestion with the handling of "forever". Seems like overkill, with runtime cost? Can't really assume a Chrono user would treat max()
as forever, and if there was special handling of some other "forever" value of the representation, they could check for it explicitly. The conversion maintains representation, so that's possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have reverted the section that require more complex changes for an elegant solution.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please review this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My point is that the chrono types do not inherently have those semantics, again for any value. If you want those semantics, then you need to code them - I don't how coercing "forever value, whatever it may be" into "max" is better than preserving the forever value and assuming the same semantics. If you convert a type with "forever = 0" into chrono, then that value means forever if its value is 0.
I see that using "max" may make it not fail so badly when you forget to put the special "forever" handling in for the chrono section, but any conversion that doesn't put the special handling in is wrong. This is covering up a programming error, and with a runtime cost.
Yes, I think it would make sense to assert on a forever conversion. That should actually lead to no code, assuming it forces you to write
if (myDuration.is_forever()) {
myChrono = myChronoForever;
} else {
myChrono = myDuration.chronoValue();
}
The assert inside the chronoValue
shouldn't generate code, because it can see that the condition is already cleared by the if it's inside. And if the forever representations match, even the if should vanish? Making it a direct assignment. Pretty certain it should.
Are you happy with the naming?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I completely agree that less damaging doesn't mean its not wrong. The assertion seems to be the thing to do. If an is_forever
member function is added it should be named isForever
to keep the code consistent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wasn't asking about the naming of my code snippet - that was just me guessing that you already had an is_forever
or something. Surely you do. And chronoValue
was my misremembering of my original valueChrono
suggestion.
I was repeating my earlier question about the name getChronoDuration
as it currently stands. Doesn't seem to fit to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
valueChrono
is a good replacement for getChronoDuration
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
features/cellular/framework/targets/RiotMicro/AT/RM1000_AT_CellularStack.cpp
Outdated
Show resolved
Hide resolved
043268d
to
b592ffd
Compare
0c67640
to
88ef9b0
Compare
63b3290
to
2f9feae
Compare
@pan- could you review please? |
2f9feae
to
705752e
Compare
Test run: FAILEDSummary: 2 of 3 test jobs failed Failed test jobs:
|
The failures are related, please review |
The following commit addresses the failure in the |
CI started |
Test run: FAILEDSummary: 2 of 3 test jobs failed Failed test jobs:
|
c79a065
to
bb013b2
Compare
This force-push should fix this failure. |
CI re-started |
Test run: FAILEDSummary: 2 of 3 test jobs failed Failed test jobs:
|
Use std::chrono literals and variables where it makes sense
bb013b2
to
2b934a2
Compare
This force-push should fix this failure. |
CI restarted. |
Test run: SUCCESSSummary: 7 of 7 test jobs passed |
Summary of changes
The chrono based functions improve readability. Using them also removes
warnings related to usage of deprecated APIs.
Impact of changes
Removes build warnings related to usage of deprecated time related functions.
Migration actions required
n/a
Documentation
n/a
Pull request type
Test results
Reviewers
@kjbracey-arm