-
Notifications
You must be signed in to change notification settings - Fork 6.9k
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
drivers: timer: nrf_rtc_timer: Add lockless, non-wraping counter reading #30829
drivers: timer: nrf_rtc_timer: Add lockless, non-wraping counter reading #30829
Conversation
bd46353
to
d8818f6
Compare
I initially thought that it will solve #30777 but it is using |
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.
In principle this seems OK, though every time we touch this code something breaks, so I'd want to stare at it more and see build results before approving.
If this is intended to support #29994's need to have shell track the time since a clock changed: it's not really going to help much. It does avoid #30777's problem of having the estimated duration wrap at 00:08:32 but still wraps at 36:24:32, so the shell command will still fail to give reliable information.
We'd need a 64-bit cycle counter to handle this sort of thing correctly.
Shall we pursue adding I've modified clock control to use |
c355ce0
to
fb6a656
Compare
59a4487
to
629afe1
Compare
I sympathize with the theory that wrapping at 36 hours won't be noticed, and it's certainly less likely than 8-plus minutes, but I don't like subtle surprises in behavior like that. Since this is Nordic only I don't object, but I also don't really approve. Carry on. I do think we need 64-bit support not only in the k_cycle API but the counter API, and am myself moving to |
Great nordic-krch. Could other relevant reviewers be added? This PR would solve some major issues for us. |
Flashed a build onto a board just now, I'll report back in a few hours. |
Could you please report back @jmgao? |
@pabigot looking at this, it seems worthwhile to me to get this in to reduce the introduced latency in users of |
Note: This PR helps reducing interrupt latency regardless of whether |
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.
Not rejecting this, just want to understand why the solution for the counter is so complex before approving the timer part. I'm still not on-board with having the shell clock data be limited to 36 hours, but the timer fix seems like a good idea.
It'd also be trivial to support 64 bit cycles by just changing last_count
to be uint64_t
. All 32-bit uses could cast the value to 32 bits, so there shouldn't be a performance impact except when advancing it wraps.
drivers/timer/nrf_rtc_timer.c
Outdated
@@ -222,13 +225,56 @@ void z_nrf_rtc_timer_compare_set(uint32_t chan, uint32_t cc_value, | |||
z_nrf_rtc_timer_compare_int_unlock(chan, key); | |||
} | |||
|
|||
uint32_t z_timer_cycle_get_32(void) | |||
{ | |||
/* Lockless algorithm for reading cycles assumes that there is an |
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.
Is it really necessary for the anchor logic to be so complex?
As far as I can tell, the longest delay that's possible is half the 24-bit span, so unless the RTC interrupt is delayed for over 256 s we know that it will be invoked before the 24-bit counter wraps at 512 s.
We already add the 24-bit delta to last_count
in the ISR. Why can't we just use last_count
as the anchor?
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.
yeah, it was a bit too much. I've updated sys_clock_cycle_get_32
to simply attempt to calculate current value based on last_count
and repeat until last count
is unchanged during the process. It is slightly faster but mainly it is lockless.
Something else has changed in the meantime, Unable to reproduce. |
This pull request has been marked as stale because it has been open (more than) 60 days with no activity. Remove the stale label or add a comment saying that you would like to have the label removed otherwise this pull request will automatically be closed in 14 days. Note, that you can always re-open a closed pull request at any time. |
Updates z_timer_cycle_get_32 to use lockless algorithm. Signed-off-by: Krzysztof Chruscinski <[email protected]>
When shell command is enabled, start/stop is timestamped to provide status. Previously, k_uptime_get() was used which locks interrupts and takes more cycles. It was leading to bluetooth failures because clock is controlled in critical path and any delays are unaccepted. Converted to use k_cycle_get_32() which has lockless implementation but is limited to 32 bits which means that status will be invalid if clock state change occurs too far in the past (~36 hours). Note was added to status command help message. Signed-off-by: Krzysztof Chruscinski <[email protected]>
629afe1
to
0e522cc
Compare
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'd like to know why there's a loop in the snapshot 32-bit cycle display. Otherwise this will be fine, if misleading when the maximum span is exceeded. A 64-bit cycle counter would solve many things.
do { | ||
anchor = *base; | ||
ret = counter_sub(counter(), anchor) + anchor; | ||
} while (anchor != *base); |
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'm not clear on what the loop is giving you here. Why not just:
uint32_t last = last_count;
return counter_sub(counter(), last) + last;
This should return a valid timestamp even if last_count
is being updated simultaneously. To the caller it's equivalent to the loop when the update happens right after the loop exit condition is met.
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 agree with @pabigot. There's no need for a loop here.
This pull request has been marked as stale because it has been open (more than) 60 days with no activity. Remove the stale label or add a comment saying that you would like to have the label removed otherwise this pull request will automatically be closed in 14 days. Note, that you can always re-open a closed pull request at any time. |
Updates z_timer_cycle_get_32 to use lockless algorithm.
Proposed algorithm is also faster than the previous one.
Additionally, updated clock control to not use locking
k_uptime_get()
:drivers: clock_control: Use k_cycle_get_32() for start/sop timestamping
When shell command is enabled, start/stop is timestamped to provide
status. Previously, k_uptime_get() was used which locks interrupts and
takes more cycles. It was leading to bluetooth failures because
clock is controlled in critical path and any delays are unaccepted.
Converted to use k_cycle_get_32() which has lockless implementation
but is limited to 32 bits which means that status will be invalid
if clock state change occurs too far in the past (~36 hours). Note was
added to status command help message.
Fixes #29994.
Signed-off-by: Krzysztof Chruscinski [email protected]