-
Notifications
You must be signed in to change notification settings - Fork 7.6k
drivers: video: video_common: refactor video_closest_frmival_stepwise() #85697
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
base: main
Are you sure you want to change the base?
Conversation
2f1c32e
to
e62d581
Compare
e62d581
to
7f723af
Compare
drivers/video/video_common.c
Outdated
|
||
/* Loose precision until landing within 32-bit range */ | ||
while (numerator_min > UINT32_MAX || numerator_step > UINT32_MAX || | ||
denominator >UINT32_MAX) { |
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.
^^ missing space, see the compliance check
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.
You are right... Should be fixed now!
7f723af
to
eaee9f1
Compare
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. |
drivers/video/video_common.c
Outdated
uint64_t numerator_min = stepwise->min.numerator; | ||
uint64_t numerator_step = stepwise->step.numerator; | ||
uint64_t numerator_goal = desired->numerator; | ||
uint64_t denominator; | ||
uint64_t numerator; |
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.
It should be uint32_t. There is a mistake in the mipi_csi2rx driver that I pushed a fix.
https://elixir.bootlin.com/linux/v6.11.1/source/include/uapi/linux/videodev2.h#L441
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.
The local variables were made 64-bit to allow storing 32-bit by 32-bit multiplication result, but this might be solved through your other comment.
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.
Yes, sorry, we indeed need uint64_t
for storing the intermediate result.
drivers/video/video_common.c
Outdated
/* Set a common denominator to these 2 values */ | ||
numerator_min *= stepwise->step.denominator; | ||
numerator_step *= stepwise->min.denominator; | ||
denominator = stepwise->min.denominator * stepwise->step.denominator; | ||
|
||
/* Loose precision until landing within 32-bit range */ | ||
while (numerator_min > UINT32_MAX || numerator_step > UINT32_MAX || | ||
denominator > UINT32_MAX) { | ||
numerator_min /= 2; | ||
numerator_step /= 2; | ||
denominator /= 2; | ||
} | ||
|
||
/* Set a common denominator to these 3 values */ | ||
numerator_min *= desired->denominator; | ||
numerator_step *= desired->denominator; | ||
numerator_goal *= denominator; | ||
denominator *= desired->denominator; | ||
|
||
/* Loose precision until landing within 32-bit range */ | ||
while (numerator_min > UINT32_MAX || numerator_step > UINT32_MAX || | ||
numerator_goal > UINT32_MAX || denominator > UINT32_MAX) { | ||
numerator_min /= 2; | ||
numerator_step /= 2; | ||
numerator_goal /= 2; | ||
denominator /= 2; | ||
} |
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 think there should be a method to avoid exceeding the range ? For example, x * y / z
could be done as x / z * y
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 did not find one the last time except converting everything to frame intervals in microseconds and compare the values like this... Which would simplify everything. Is it good enough?
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.
Yes, I see now, this is not a simple problem ...
- Would it be possible and simpler if we activate CONFIG_FPU to do the computation ?
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.
Maybe converting back and forth with integers and floats would give good precision, but not give exact fractional results, i.e. 1000/9999 vs 1/10. Maybe that works everywhere though!
Should frame intervals only be stored as nanosecond instead of fractions to avoid these kind of problems?
I just pushed a compromise performing the comparison as nanoseconds (using video_frmival_nsec()
, could lead to different results in extreme "tie-breaker" situations), but storing the result as a fraction (like currently).
drivers/video/video_common.c
Outdated
uint64_t numerator_min = stepwise->min.numerator; | ||
uint64_t numerator_step = stepwise->step.numerator; | ||
uint64_t numerator_goal = desired->numerator; | ||
uint64_t denominator; | ||
uint64_t numerator; |
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.
Yes, sorry, we indeed need uint64_t
for storing the intermediate result.
drivers/video/video_common.c
Outdated
/* Set a common denominator to these 2 values */ | ||
numerator_min *= stepwise->step.denominator; | ||
numerator_step *= stepwise->min.denominator; | ||
denominator = stepwise->min.denominator * stepwise->step.denominator; | ||
|
||
/* Loose precision until landing within 32-bit range */ | ||
while (numerator_min > UINT32_MAX || numerator_step > UINT32_MAX || | ||
denominator > UINT32_MAX) { | ||
numerator_min /= 2; | ||
numerator_step /= 2; | ||
denominator /= 2; | ||
} | ||
|
||
/* Set a common denominator to these 3 values */ | ||
numerator_min *= desired->denominator; | ||
numerator_step *= desired->denominator; | ||
numerator_goal *= denominator; | ||
denominator *= desired->denominator; | ||
|
||
/* Loose precision until landing within 32-bit range */ | ||
while (numerator_min > UINT32_MAX || numerator_step > UINT32_MAX || | ||
numerator_goal > UINT32_MAX || denominator > UINT32_MAX) { | ||
numerator_min /= 2; | ||
numerator_step /= 2; | ||
numerator_goal /= 2; | ||
denominator /= 2; | ||
} |
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.
Yes, I see now, this is not a simple problem ...
- Would it be possible and simpler if we activate CONFIG_FPU to do the computation ?
6667c1c
to
0d7bacf
Compare
force-push:
|
0d7bacf
to
1644eb2
Compare
Force-push:
|
That sounds more than enough! I will try that now... |
1644eb2
to
7561345
Compare
Force-push:
It seems like Otherwise, feel free to validate this PR only and this will be scoped to only |
I'll go fix the CI now, please wait a little more... |
7561345
to
a9b9c54
Compare
Force-push:
|
By making all the computation in nanoseconds, we start to loose a bit of precision when the numerator and denominator are both huge:
This test was passing without imprecision. |
a9b9c54
to
9cc9fe1
Compare
Avoid an integer overflow by dividing the numerator and denominator by two (dropping one bit of precision), which preserve the ratio. Result still accurate, as only done on values larger than UINT32_MAX. fixes CID-444385, CID-444388 and CID-444389 Signed-off-by: Josuah Demangeon <[email protected]>
9cc9fe1
to
34d38bd
Compare
|
Now CI passes, but I had to introduce between 10 and 1000 nanoseconds of imprecision. |
Double is not usable as the computation relies on integer division to select the correct step, with |
Avoid an integer overflow by reducing the precision until the result is checked to fit in 32-bit. This is possible by simplifying fractions by 2, which should not affect the result significantly as this is only done when the values are extremely large (too large to fit 32-bit int).
Also adding a test case that would overflow without proper handling.
Fixes: