-
Notifications
You must be signed in to change notification settings - Fork 6.8k
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
Zephyr support for ABIs without a defined floating-point calling convention #32192
Comments
BTW I'll be making another ticket soon(TM) for the specific weird platform in question, if you're wondering. |
@pabigot FYI |
As an aside, I am somewhat confused about what should be a question versus bug versus enhancement versus feature request. Everything I'm doing seems to fall into two (or more) of those categories at once. Any input as to my (mis)use of these labels would be appreciated. |
See #32195. Long story short, GCC does not have a defined softfloat ABI for AArch64, as AArch64 does not have an official softfloat ABI. (Interestingly, recent versions of Clang do have a defined softfloat ABI for AArch64. See e.g. https://godbolt.org/z/TGe38f ) |
Interesting. We have historically variant terminology around floating point. Perhaps we could benefit from a more precise taxonomy for floating point support that selects the floating point support level from the options identified in the issue introduction (isn't there a fourth, hardware floating point operations with arguments passed on stack?). So this could be a Kconfig choice like:
where with Or if that's too complex, just As to the potential solutions: I made several attempts to use a 64-bit fixed point representation in developing this API, and they all failed because of truncation in intermediate values due to the wide range of local and remote clock speeds that need to be supported. So I don't like 3 or 4. We could revisit that if the timesync API becomes critical to Zephyr, rather than just the applications that need it. I prefer 1 (leave the API in
Only on the function definition? If they're also going to reject a declaration/prototype, we have a different (albeit minor) problem related to documentation generation. 2021-02-16: see also #32373 (comment) and surrounding context. |
@tejlmand might be good to discuss part of this in the toolchain working group and how to convey the toolchain features (runtime checks, Cmake, Kconfig, etc..) |
I knew I shouldn't have left that out :-) Yes, this mode exists, although I haven't really run across any architectures which have compiler flags to differentiate this mode. There are ABIs with hardware floating-point that occasionally pass arguments outside dedicated floating-point registers, but they tend to be happenstance as opposed to an explicit selectable variant ABI, if that makes sense.
+1 from me on this.
Assuming that 3 or 4 functioned properly, would you still dislike it? Or is this "just" a statement of "I don't think 3 or 4 are feasible"?
Oh, so it wasn't the skew value itself that was the issue, but the resulting arithmetic with the clock speeds? Interesting, and I could see why that could be an issue. If I came up with a solution that handled the entire range properly (I know this is nontrivial, to put it mildly), would you be interested in taking a look at it?
I mean, we would consider it useful, although obviously not in its current state.
Hmm. I suppose this comes down to the question of how exactly to use Kconfig. In particular I'm used to module features that are dependent on some global feature, rather than directly using said global feature. E.g. Not the end of the world either way I suppose.
Good point. Ditto format string support for floats/doubles, among other things. This mainly came up because currently
So far as I can tell this is the case, luckily, on both GCC and clang: https://godbolt.org/z/n68zsG |
The latter.
Yes, if you want to give it a try I'll certainly take a look. The solutions I came up with mostly worked, but in addition to overflow causing divergence, the reduced accuracy led to significantly longer periods to converge to the right answer (hours, instead of minutes). The API is also used to measure the skew between independent clocks, such as a 32 KiHz crystal oscillator and the main CPU clock. The range of frequencies for which there are use cases is 1 Hz (1 s) to perhaps 4 GHz (250 ps) or even higher. Restricting frequency values to (2^N)*(5^M) might be a reasonable restriction, if that helps. The magnitude of the time differences involved in calculating skews may also be large (counts that exceed 2^32). Floating point is really suited to this; fixed point isn't an obvious good choice. Measuring skew isn't currently critical to any core Zephyr functionality, so effort required, and potential increase in code size to the majority of systems where floats could be used, are criteria for a trade-off between making it optional or selecting between float or fixed-point implementations.
That interests me; I think there are only two people, one of them me, who actively supported this capability.
If the part of the original PR that added a generic "convert Zephyr local clock to realtime" API had gotten any support, that'd be the situation we're in, but it didn't. Zephyr commonly uses Kconfig to allow applications to say "I don't need that feature, don't make me pay for it", which applies in this case.
That should be covered; cbprintf does it without floating point operations.
That wasn't intentional, it's just there was no reason to support disabling it. I have no problem with making it optional. |
Hmm. The current timeutil sync API has both What's the desired overall accuracy?
Yep. Just a (somewhat trivial/obvious) example of an optional feature that requires floating-point. Though I'll have a patch incoming for that - there's one spot in the current code that's unreachable at runtime but that the compiler can't figure out, and errors out in the FLOAT_UNSUPPORTED case (...and I think, emitting needless calls to softfloat APIs in the soft float case, although I haven't actually checked.). Simple fix.
It may be a case of a solution in need of a problem, but having a combination of an accurate timesource that you don't want to use for everything (due to power / latency / etc) and an inaccurate but "easy" timesource is not uncommon. So, perhaps just 1 as a short-to-mid-term solution, leaving open the possibility of 3 or 4 down the line? |
True.
I want to be able to correct local clocks to about 2 ppm, like I'd get from a quality external RTC, assuming the skew is not affected by environmental concerns (e.g. temperature). This helps with correlating events recorded on distinct deployed data loggers, limiting the timestamp error to about +/- 1 minute per year. So the estimated skew has to be about that accurate.
Please add me as a reviewer when that's submitted if github doesn't do so.
Yes. |
Sure, shall do.
Ditto. (On both of these I'm largely blocked on #32237, but that "should" be resolved shortly I think. At the very least workaround-able.)
Great, thank you for the clear requirements here. A question (pedantic I am aware... "being pedantic" sometimes seems like my job description):
|
I meant that to be addressed by:
because I know temperature is likely to be an issue. In my applications the skew does converge (the local clock for me is the Zephyr tick counter from a 25 ppm 32 KiHz crystal oscillator; the reference clock is TAI from a Linux host using NTP, transferred over Bluetooth). So yes, I'm assuming that the local clock local runs at a constant unknown rate close to but not exactly its nominal rate. E.g. 32767.181 Hz instead of 32768.000 Hz. The skew combined with a time measured in the local clock gets me a pretty accurate estimate of the time passed in the reference clock. |
Over a single update's time period I assume? That makes sense. |
Tagging myself in.
+1 here too. Being a fixed point math adept myself I understand the motivation for trying to solve the timeutil API, however this should be dealt separately from the |
Introduction
Even with all FPU configuration options disabled, Zephyr currently requires a defined floating-point calling convention, due to several functions in
timeutil_skew_*
taking and using floating-point values.Note that this is distinct from having soft-float enabled. (There's really three alternatives here: an ABI that uses hardware floating-point operations and that passes floating-point values in hardware registers, an ABI that uses software floating-point operations and that does not use floating-point registers (instead passing floating-point values between functions using e.g. general-purpose registers)), or an ABI that neither allows floating-point operations nor allows floats to be passed between functions at all. Roughly: hard-float, soft-float, and no-float.)
Problem description
GCC and clang will error if they encounter a function defined with a floating-point type with no-float (as defined above). This results in being unable to compile or use Zephyr on any such platforms, even if the
timeutil_*
functions taking floats are unused and GC'd out.Proposed change
Either:
timeutil_*
functions that use floating-point arguments.and/or
timeutil_skew_*
functions into their own file.and/or
timeutil_*
functions that use floating-point values or arguments to not use floating-point values or arguments.and/or
I am able to do these changes; I do not wish to go ahead with these until/unless someone pokes at any obvious holes in the above.
Detailed RFC
Option 1 would be as follows:
lib/os/Kconfig
calledCONFIG_ENABLE_FLOAT_TIMEUTIL
[n.b. I am terrible at naming things.]include/sys/timeutil.h
that rely on floating-point types behind the flag defined in 1.lib/os/timeutil.c
that were gated in 2 behind the flag defined in 1.tests/util/timeutil/test_sync.c
that use gated function definitions behind the flag defined in 1. (Is there a "proper" way to make a unit test require a feature?)Option 2 would be as follows:
include/sys/timeout_sync.h
.timeout_sync_*
-related functions and types fromtimeout.h
totimeout_sync.h
timeout.h
totimeout_sync.h
if they are only usingtimeout_sync.h
functions. (I think this is onlytest_sync.c
.)timeout_sync.h
totimeout.h
. Required for backwards compatibility.timeout_sync_*
-related functions and types fromtimeout.c
totimeout_sync.c
timeout_sync.c
to CMakeLists.txtOption 3/4 would be as follows (Note: replace
change
withadd a new version with
as appropriate.):float skew
to an int64_t [way overkill, but oh well], defined as a fixed-point type of absolute clockspeed in units of, oh, 2^-24th of a part per billion. (This gives a clockspeed range of of 0-1100, if you're wondering why the weird and seemingly-arbitrary unit. Units of 2^-32 would potentially be better, but would give a range of 0-4, which I could see someone overflowing. If your clock is running 1100x realtime you've got worse problems. You could choose something in the range 24-32; I just am generally lothe to pick shift values that aren't a multiple of 8 for various reasons. Ditto, the reason for having the units be a twos-based fraction of a decimal fraction (2^-24th of a part per billion) is to allowtimeutil_sync_skew_to_ppb
to be reasonably quick... which may be an overoptimization.)timeutil_sync_*
functions to use said fixed-point value instead of floats or doubles.Proposed change (Detailed)
I'm honestly not sure how this section is supposed to be different than the above section.
Dependencies
Any other APIs added that use floating-point in a non-optional manner would break this.
Concerns and Unresolved Questions
See above.
Option 3 would be a breaking change. Option 2 could be a breaking change in certain cases, if
timeutil.h
didn't includetimeutil_skew.h
Alternatives
Listed inline above.
The text was updated successfully, but these errors were encountered: